summaryrefslogtreecommitdiff
path: root/libjava/classpath/tools/gnu
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/tools/gnu
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/tools/gnu')
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/FileSystemClassLoader.java312
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/IOToolkit.java216
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/MalformedInputEvent.java110
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/MalformedInputListener.java56
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/NotifyingInputStreamReader.java423
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/StringToolkit.java84
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java81
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java95
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletTag.java489
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java133
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java139
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java53
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/Main.java323
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java72
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java178
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java448
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java76
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java148
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java560
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java356
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/common/CallbackUtil.java145
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/common/ClasspathToolParser.java239
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/common/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/common/Persistent.java87
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/common/ProviderUtil.java163
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/common/SecurityProviderInfo.java99
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/AbstractDoclet.java1386
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/DocletConfigurationException.java54
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOption.java56
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionColonSeparated.java76
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFile.java77
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFlag.java69
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionPackageWildcard.java124
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionString.java68
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/InlineTagRenderer.java46
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/InvalidPackageWildcardException.java51
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/PackageGroup.java58
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/PackageMatcher.java152
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/StandardTaglet.java100
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/TagletPrinter.java46
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/debugdoclet/DebugDoclet.java174
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/CssClass.java300
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/ExternalDocSet.java187
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlDoclet.java3887
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlPage.java535
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlTagletContext.java65
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver.java2451
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver1_4.java84
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/HtmlRepairer.java690
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/TargetContext.java103
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTranslet.java460
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletConfigurationException.java53
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletException.java63
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletOptions.java62
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/JarClassLoader.java91
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/OutputFileInfo.java66
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java62
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/getopt/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/getopt/Option.java266
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/getopt/OptionException.java58
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/getopt/OptionGroup.java268
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/getopt/Parser.java495
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/AbstractTagImpl.java107
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ArrayCharacterIterator.java121
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocImpl.java1260
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocProxy.java169
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocReflectedImpl.java219
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ConstructorDocImpl.java59
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/Debug.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/DirectoryTree.java74
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/DocImpl.java1090
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ErrorReporter.java121
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ExecutableMemberDocImpl.java427
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/FieldDocImpl.java409
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocPackageDoc.java56
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocRootDoc.java56
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/InheritDocTagImpl.java103
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/JavadocWrapper.java53
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/LinkTagImpl.java63
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/Main.java1854
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/MemberDocImpl.java235
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/MethodDocImpl.java64
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/PackageDocImpl.java223
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParamTagImpl.java81
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParameterImpl.java69
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParseException.java51
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/Parser.java1064
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ProgramElementDocImpl.java177
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/RootDocImpl.java1334
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/SeeTagImpl.java215
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/SerialFieldTagImpl.java128
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/SourcePositionImpl.java77
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagContainer.java52
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagImpl.java60
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/TemporaryStore.java132
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/TextTagImpl.java56
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ThrowsTagImpl.java105
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/Timer.java88
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/TimerDoclet.java104
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeImpl.java109
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeVariableImpl.java108
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/ValueTagImpl.java65
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/WritableType.java44
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AdditionExpression.java86
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AndExpression.java57
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryBitwiseExpression.java68
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryComputationExpression.java92
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryEqualityExpression.java89
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryExpression.java51
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryLogicalExpression.java64
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryRelationExpression.java82
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryShiftExpression.java66
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BitShiftRightExpression.java57
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/CircularExpressionException.java52
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConditionalExpression.java74
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantBoolean.java84
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantByte.java74
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantChar.java98
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantDouble.java79
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantExpression.java52
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantFloat.java79
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantInteger.java79
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantLong.java84
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantNull.java66
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantShort.java74
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantString.java74
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Context.java62
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/DivisionExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EqualExpression.java72
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Evaluator.java148
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EvaluatorEnvironment.java46
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ExclusiveOrExpression.java57
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Expression.java44
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanOrEqualExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IdentifierExpression.java89
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IllegalExpressionException.java52
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/InclusiveOrExpression.java57
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanOrEqualExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalAndExpression.java52
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalNotExpression.java60
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalOrExpression.java52
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ModuloExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/MultiplicationExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NegateExpression.java66
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotEqualExpression.java72
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotExpression.java60
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftLeftExpression.java57
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftRightExpression.java57
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/SubtractionExpression.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Type.java60
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/TypeCastExpression.java87
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnaryExpression.java49
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnknownIdentifierException.java47
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/java-expression.g471
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Action.java51
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Creator.java251
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Entry.java70
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Extractor.java127
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Indexer.java142
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Lister.java112
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Main.java293
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/Updater.java98
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jar/WorkSet.java83
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jarsigner/HashUtils.java124
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarSigner.java173
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarVerifier.java343
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jarsigner/Main.java689
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jarsigner/Messages.java119
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/jarsigner/SFHelper.java491
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/java2xhtml/Java2xhtml.java1354
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java376
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/CniIncludePrinter.java80
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/CniPrintStream.java274
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java129
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/FieldHelper.java99
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/GcjhMain.java153
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/JniHelper.java120
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/JniIncludePrinter.java169
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/JniPrintStream.java115
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/JniStubPrinter.java109
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/Keywords.java172
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/Main.java468
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/MethodHelper.java122
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/PackageWrapper.java54
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/PathOptionGroup.java147
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/Printer.java139
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/javah/Text.java60
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/CACertCmd.java313
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/CertReqCmd.java475
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/Command.java1228
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/DeleteCmd.java280
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/ExportCmd.java328
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/GenKeyCmd.java602
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java232
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/ImportCmd.java930
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java407
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java395
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/ListCmd.java432
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/Main.java329
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/Messages.java118
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/PrintCertCmd.java143
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/SelfCertCmd.java440
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java318
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/native2ascii/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/native2ascii/Native2ASCII.java194
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/orbd/Main.java226
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/orbd/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContext.java152
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContextMap.java87
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentMap.java454
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/AbstractMethodGenerator.java53
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/ClassRmicCompiler.java1834
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/CompilationError.java69
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/Generator.java145
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/GiopIo.java129
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/HashFinder.java100
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/Main.java293
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/MethodGenerator.java302
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/RMICException.java70
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/RmiMethodGenerator.java297
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/RmicBackend.java48
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java694
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/SourceRmicCompiler.java189
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/Variables.java154
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmic/WrapUnWrapper.java99
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java243
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl_Stub.java556
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmid/Main.java258
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmid/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmid/PersistentBidiHashTable.java269
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Main.java232
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Messages.java67
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmiregistry/PersistentHashTable.java262
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl.java138
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Skel.java278
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Stub.java263
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/serialver/Messages.java68
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/serialver/SerialVer.java179
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/AuthorTaglet.java293
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/CodeTaglet.java101
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/CopyrightTaglet.java123
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/DeprecatedTaglet.java132
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/GenericTaglet.java157
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/GnuExtendedTaglet.java48
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/SinceTaglet.java161
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/TagletContext.java60
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/ValueTaglet.java130
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/taglets/VersionTaglet.java153
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/tnameserv/Main.java115
-rw-r--r--libjava/classpath/tools/gnu/classpath/tools/tnameserv/Messages.java67
255 files changed, 57605 insertions, 0 deletions
diff --git a/libjava/classpath/tools/gnu/classpath/tools/FileSystemClassLoader.java b/libjava/classpath/tools/gnu/classpath/tools/FileSystemClassLoader.java
new file mode 100644
index 000000000..a6bd72831
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/FileSystemClassLoader.java
@@ -0,0 +1,312 @@
+/* gnu.classpath.tools.FileSystemClassLoader
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+
+/**
+ * A <code>ClassLoader</code> implementation which looks for classes
+ * on the local filesystem given a standard search path.
+ */
+public class FileSystemClassLoader extends ClassLoader {
+
+ private File[] pathComponents;
+
+ /**
+ * Initialize the class loader with a normal path string. The path
+ * string should contain path components separated by {@link
+ * File.pathSeparator}. Each path component should either denote a
+ * directory or a .jar or .zip file.
+ */
+ public FileSystemClassLoader(String path)
+ {
+ List components = new ArrayList();
+ for (StringTokenizer st = new StringTokenizer(path, File.pathSeparator); st.hasMoreTokens(); ) {
+ File pathComponent = new File(st.nextToken());
+ components.add(pathComponent);
+ if (pathComponent.exists() && !pathComponent.isDirectory()) {
+ List subComponents = tryGetJarFileClassPathComponents(pathComponent);
+ if (null != subComponents) {
+ components.addAll(subComponents);
+ }
+ }
+ }
+ File[] componentArray = new File[components.size()];
+ this.pathComponents = (File[])components.toArray(componentArray);
+ }
+
+ /**
+ * Initialize the class loader with an array of path
+ * components. Each path component should either denote a
+ * directory or a .jar or .zip file.
+ */
+ public FileSystemClassLoader(File[] pathComponents)
+ {
+ this.pathComponents = pathComponents;
+ for (int i = 0; i < pathComponents.length; ++i) {
+ if (!pathComponents[i].exists()) {
+ System.err.println("WARNING: Path component '" + pathComponents[i] + "' not found.");
+ }
+ }
+ }
+
+ public Class loadClass(String name)
+ throws ClassNotFoundException {
+
+ return super.loadClass(name);
+ }
+
+ public Class findClass(String name)
+ throws ClassNotFoundException {
+
+ byte[] b = loadClassData(name);
+ return defineClass(name, b, 0, b.length);
+ }
+
+ public URL findResource(String name)
+ {
+ StreamInfo streamInfo = getResourceStream(name);
+ if (null == streamInfo) {
+ return super.findResource(name);
+ }
+ else {
+ try {
+ return streamInfo.getURL();
+ }
+ catch (MalformedURLException e) {
+ System.err.println("WARNING: In FileSystemClassLoader: could not derive URL from file or jar entry: " + e.toString());
+ return null;
+ }
+ }
+ }
+
+ private byte[] readFromStream(InputStream in, long size)
+ throws IOException
+ {
+ byte[] result = new byte[(int)size];
+ int nread = 0;
+ int offset = 0;
+ while (offset < size && (nread = in.read(result, offset, (int)(size - offset))) >= 0) {
+ offset += nread;
+ }
+ in.close();
+ return result;
+ }
+
+ private byte[] readFromStream(StreamInfo streamInfo)
+ throws IOException
+ {
+ InputStream in = streamInfo.openStream();
+ long size = streamInfo.getSize();
+
+ byte[] result = new byte[(int)size];
+ int nread = 0;
+ int offset = 0;
+ while (offset < size && (nread = in.read(result, offset, (int)(size - offset))) >= 0) {
+ offset += nread;
+ }
+ in.close();
+ return result;
+ }
+
+ private static interface StreamInfo
+ {
+ public InputStream openStream()
+ throws IOException;
+ public long getSize();
+ public URL getURL()
+ throws MalformedURLException;
+ }
+
+ private static class FileStreamInfo
+ implements StreamInfo
+ {
+ File file;
+
+ FileStreamInfo(File file)
+ {
+ this.file = file;
+ }
+
+ public InputStream openStream()
+ throws IOException
+ {
+ return new FileInputStream(file);
+ }
+
+ public long getSize()
+ {
+ return file.length();
+ }
+
+ public URL getURL()
+ throws MalformedURLException
+ {
+ return file.toURL();
+ }
+ }
+
+ private static class JarStreamInfo
+ implements StreamInfo
+ {
+ private File file;
+ private JarFile jarFile;
+ private JarEntry jarEntry;
+
+ JarStreamInfo(File file, JarFile jarFile, JarEntry jarEntry)
+ {
+ this.file = file;
+ this.jarFile = jarFile;
+ this.jarEntry = jarEntry;
+ }
+
+ public InputStream openStream()
+ throws IOException
+ {
+ return jarFile.getInputStream(jarEntry);
+ }
+
+ public long getSize()
+ {
+ return jarEntry.getSize();
+ }
+
+ public URL getURL()
+ throws MalformedURLException
+ {
+ String urlString = "jar:" + file.toURL() + "!/" + jarEntry.getName();
+ return new URL(urlString);
+ }
+ }
+
+ private StreamInfo getResourceStream(String path)
+ {
+ for (int i = 0; i < pathComponents.length; ++i) {
+ try {
+ File parent = pathComponents[i];
+ if (parent.isDirectory()) {
+ File file = new File(parent, path);
+ if (file.exists()) {
+ return new FileStreamInfo(file);
+ }
+ }
+ else {
+ JarFile jarFile = new JarFile(parent, false, JarFile.OPEN_READ);
+ JarEntry jarEntry = jarFile.getJarEntry(path);
+ if (null != jarEntry) {
+ return new JarStreamInfo(parent, jarFile, jarEntry);
+ }
+ }
+ }
+ catch (IOException ignore) {
+ }
+ }
+ return null;
+ }
+
+ private byte[] loadClassData(String className)
+ throws ClassNotFoundException
+ {
+ String classFileName = className.replace('.', File.separatorChar) + ".class";
+ StreamInfo streamInfo = getResourceStream(classFileName);
+
+ try {
+ if (null != streamInfo) {
+ return readFromStream(streamInfo);
+ }
+ }
+ catch (IOException ignore) {
+ }
+
+ throw new ClassNotFoundException(className);
+ }
+
+ private static List tryGetJarFileClassPathComponents(File file)
+ {
+ try {
+ JarFile jarFile = new JarFile(file, false, JarFile.OPEN_READ);
+ Manifest manifest = jarFile.getManifest();
+ if (null != manifest) {
+ Attributes mainAttributes = manifest.getMainAttributes();
+ if (null != mainAttributes) {
+ String classPath = mainAttributes.getValue(Attributes.Name.CLASS_PATH);
+ if (null != classPath) {
+ List result = new LinkedList();
+ StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(classPath));
+ tokenizer.resetSyntax();
+ tokenizer.wordChars(0, Integer.MAX_VALUE);
+ tokenizer.whitespaceChars(9, 9); // tab
+ tokenizer.whitespaceChars(10, 10); // lf
+ tokenizer.whitespaceChars(13, 13); // cr
+ tokenizer.whitespaceChars(32, 32); // space
+ tokenizer.quoteChar('"');
+ int token;
+ while ((token = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) {
+ if (StreamTokenizer.TT_WORD == token) {
+ result.add(new File(file.getParentFile(), tokenizer.sval));
+ }
+ }
+ return result;
+ }
+ }
+ }
+ }
+ catch (IOException ignore) {
+ }
+ return null;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/IOToolkit.java b/libjava/classpath/tools/gnu/classpath/tools/IOToolkit.java
new file mode 100644
index 000000000..e0ee7ba4f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/IOToolkit.java
@@ -0,0 +1,216 @@
+/* gnu.classpath.tools.IOToolkit
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import java.util.Set;
+
+/**
+ * Provides various I/O-related helper methods.
+ *
+ * @author Julian Scheid
+ */
+public class IOToolkit
+{
+ /**
+ * Prevents instantiation.
+ */
+ private IOToolkit() {}
+
+ /**
+ * Read all binary data from the given InputStream and write it to
+ * the given OutputStream. This method doesn't close either
+ * stream.
+ *
+ * @param in the stream from which to read data
+ * @param out the stream to which to write data
+ */
+ public static void copyStream(InputStream in, OutputStream out)
+ throws IOException
+ {
+ byte[] buf = new byte[256];
+ int nread;
+
+ while ((nread = in.read(buf)) >= 0) {
+ out.write(buf, 0, nread);
+ }
+ }
+
+ /**
+ * Read all character data from the given Reader and write it to
+ * the given Writer. This method doesn't close either stream.
+ *
+ * @param in the Reader from which to read character data
+ * @param out the Writer to which to write character data
+ */
+ public static void copyStream(Reader in, Writer out)
+ throws IOException
+ {
+ char[] buf = new char[256];
+ int nread;
+
+ while ((nread = in.read(buf)) >= 0) {
+ out.write(buf, 0, nread);
+ }
+ }
+
+ /**
+ * Recursively copy the contents of the input directory to the
+ * output directory. The output directory is created if it doesn't
+ * exist. If the output directory doesn't exist and can't be
+ * created, an IOException is thrown.
+ *
+ * @param sourceDir source directory from which to copy files
+ * @param targetDir target directory to which to copy files
+ * @param recursive if true, recursively copy subdirectoryies
+ * @param excludeDirs if non null, must be a Set of String. Each
+ * element from the set specifies the name of a direct
+ * subdirectory of the source directory which should be excluded
+ * from recursive copying.
+ */
+ public static void copyDirectory(File sourceDir, File targetDir,
+ boolean recursive,
+ Set excludeDirs)
+ throws IOException
+ {
+ if (!targetDir.exists() && !targetDir.mkdirs()) {
+ throw new IOException("Cannot create directory " + targetDir);
+ }
+
+ File[] sourceFiles = sourceDir.listFiles();
+ for (int i=0; i<sourceFiles.length; ++i) {
+ if (sourceFiles[i].isDirectory()) {
+ if (recursive && (null == excludeDirs
+ || !excludeDirs.contains(sourceFiles[i].getName()))) {
+ File targetSubDir = new File(targetDir,
+ sourceFiles[i].getName());
+ if (targetSubDir.exists() || targetSubDir.mkdir()) {
+ copyDirectory(sourceFiles[i], targetSubDir, recursive, null);
+ }
+ else {
+ throw new IOException("Cannot create directory " + targetSubDir);
+ }
+ }
+ }
+ else {
+ copyFile(sourceFiles[i], new File(targetDir, sourceFiles[i].getName()));
+ }
+ }
+ }
+
+ /**
+ * Copy the contents of the input file to the output file. The
+ * output file's parent directory must exist.
+ *
+ * @param sourceFile specifies the file to copy
+ * @param targetFile specifies the file to create
+ */
+ public static void copyFile(File sourceFile, File targetFile)
+ throws IOException
+ {
+ InputStream in = new FileInputStream(sourceFile);
+ OutputStream out = new FileOutputStream(targetFile);
+ int nread;
+ byte[] buf = new byte[512];
+ while ((nread = in.read(buf)) >= 0) {
+ out.write(buf, 0, nread);
+ }
+ in.close();
+ out.close();
+ }
+
+ /**
+ * Read the (remaining) contents of the given reader into a char
+ * array. This method doesn't close the reader when it is done.
+ *
+ * @param reader the Reader to read characters from
+ * @return an array with the contents of the Reader
+ */
+ public static char[] readFully(Reader reader)
+ throws IOException
+ {
+ StringWriter writer = new StringWriter();
+ final int readBufferSize = 256;
+ char[] chunk = new char[readBufferSize];
+ int nread;
+ while ((nread=reader.read(chunk))>=0) {
+ writer.write(chunk,0,nread);
+ }
+ StringBuffer buffer = writer.getBuffer();
+ char[] result = new char[buffer.length()];
+ buffer.getChars(0, buffer.length(), result, 0);
+ return result;
+ }
+
+ public static String getLineFromFile(File file, int line)
+ throws IOException
+ {
+ FileReader reader = new FileReader(file);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ while (line > 1) {
+ bufferedReader.readLine();
+ -- line;
+ }
+ String result = bufferedReader.readLine();
+ reader.close();
+ return result;
+ }
+
+ public static String getColumnDisplayLine(int column)
+ {
+ StringBuffer result = new StringBuffer();
+ while (column > 0) {
+ result.append(' ');
+ --column;
+ }
+ result.append('^');
+ return result.toString();
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/MalformedInputEvent.java b/libjava/classpath/tools/gnu/classpath/tools/MalformedInputEvent.java
new file mode 100644
index 000000000..951766f6a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/MalformedInputEvent.java
@@ -0,0 +1,110 @@
+/* gnu.classpath.tools.MalformedInputEvent
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools;
+
+import java.util.EventObject;
+
+/**
+ * Encapsulates information about malformed input encountered by a
+ * {@link NotifyingInputStreamReader}.
+ *
+ * You can use {@link getSource()} to fetch a reference to the
+ * <code>NotifyingInputStreamReader</code> which encountered the
+ * malformed input.
+ *
+ * @author Julian Scheid
+ */
+public class MalformedInputEvent
+ extends EventObject
+{
+ private int lineNumber;
+ private int columnNumber;
+ private int length;
+
+ MalformedInputEvent(NotifyingInputStreamReader source,
+ int lineNumber,
+ int columnNumber,
+ int length)
+ {
+ super(source);
+ this.columnNumber = columnNumber;
+ this.lineNumber = lineNumber;
+ this.length = length;
+ }
+
+ /**
+ * Return the 1-based line number where the malformed input begins
+ * in the stream read by the
+ * <code>NotifyingInputStreamReader</code>.
+ */
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ /**
+ * Return the 0-based column number where the malformed input
+ * begins in the stream read by the
+ * <code>NotifyingInputStreamReader</code>.
+ */
+ public int getColumnNumber()
+ {
+ return columnNumber;
+ }
+
+ /**
+ * Return the length (in bytes) of the malformed input encountered
+ * by the <code>NotifyingInputStreamReader</code>. Note that a
+ * consecutive run of malformed input isn't necessarily reported
+ * as a whole; depending on the <code>Charset</code> and
+ * implementation details of <code>CharsetDecoder</code>, the run
+ * could be reported in chunks down to individual bytes.
+ */
+ public int getLength()
+ {
+ return length;
+ }
+
+ public String toString()
+ {
+ return "MalformedInputEvent{line=" + lineNumber
+ + ",column=" + columnNumber
+ + ",length=" + length
+ + "}";
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/MalformedInputListener.java b/libjava/classpath/tools/gnu/classpath/tools/MalformedInputListener.java
new file mode 100644
index 000000000..53f806bf8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/MalformedInputListener.java
@@ -0,0 +1,56 @@
+/* gnu.classpath.tools.MalformedInputListener
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools;
+
+/**
+ * Classes implementing this interface can be notified when a {@link
+ * NotifyingInputStreamReader} encounters malformed input.
+ *
+ * @author Julian Scheid
+ */
+public interface MalformedInputListener
+{
+ /**
+ * Invoked when a <code>NotifyingInputStreamReader</code> this
+ * listener is registered with encounters malformed input.
+ *
+ * @param MalformedInputEvent contains detailed information about
+ * the event.
+ */
+ public void malformedInputEncountered(MalformedInputEvent event);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/NotifyingInputStreamReader.java b/libjava/classpath/tools/gnu/classpath/tools/NotifyingInputStreamReader.java
new file mode 100644
index 000000000..70e19b1d3
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/NotifyingInputStreamReader.java
@@ -0,0 +1,423 @@
+/* gnu.classpath.tools.NotifyingInputStreamReader
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Similar to {@link java.io.InputStreamReader}, but can give
+ * notification when malformed input is encountered.
+ *
+ * <p> Users of this class can register interest in the event of
+ * malformed input by calling {@link
+ * #addMalformedInputListener}. Each time a run of malformed input
+ * data is encountered, all listener objects are notified. For
+ * instance, this allows the calling code to inform the user about
+ * problems in the input stream. </p>
+ *
+ * <p> <strong>Background:</strong> The default
+ * <code>InputStreamReader</code> implementation will ignore
+ * malformed input, silently replacing it with the default
+ * replacement string (usually the question mark). Alternatively, you
+ * can configure a <code>CharsetDecoder</code> for the default
+ * <char>InputStreamReader</code> implementation, instructing it to
+ * ignore malformed input without replacing it; to replace it with a
+ * different string; or to throw an exception when malformed input is
+ * encountered. However, you cannot configure an
+ * <code>InputStreamReader</code> to gracefully handle malformed data
+ * but notify the client code about such
+ * problems. <code>NotifyingInputStreamReader</code> fills this
+ * gap. </p>
+ *
+ * @author Julian Scheid
+ */
+public class NotifyingInputStreamReader
+ extends Reader
+{
+ /**
+ * The default size (in bytes) for byteBuf, i.e. the size of data
+ * chunks read from the underlying input stream.
+ */
+ private static final int DEFAULT_INPUT_BUFFER_SIZE = 64;
+
+ /**
+ * The default size (in chars) for charBuf. This should be large
+ * enough to hold a decoded chunk of input data for the Charset
+ * with the minimum number of bytes per character. Since the
+ * minimum number of bytes per character for usual Charsets is
+ * one, this number should be identical to
+ * DEFAULT_INPUT_BUFFER_SIZE.
+ */
+ private static final int DEFAULT_OUTPUT_BUFFER_SIZE = 64;
+
+ /**
+ * The underlying InputStream.
+ */
+ private InputStream in;
+
+ /**
+ * The CharsetDecoder used to decode the underlying stream.
+ */
+ private CharsetDecoder decoder;
+
+ /**
+ * Holds bytes already read from the underlying stream, but not
+ * yet decoded.
+ */
+ private ByteBuffer byteBuffer;
+
+ /**
+ * Holds characters already decoded, but not yet fetched via
+ * read().
+ */
+ private CharBuffer charBuffer;
+
+ /**
+ * This is the primitive byte array wrapped in byteBuffer for
+ * passing to to InputStream.read().
+ */
+ private byte[] readBuffer;
+
+ /**
+ * Keeps track of the current line number (1-based).
+ */
+ private int lineNumber = 1;
+
+ /**
+ * Keeps track of the current column number (0-based).
+ */
+ private int columnNumber = 0;
+
+ /**
+ * Becomes true as soon as EOF has been reached in the underlying
+ * InputStream. At this point, byteBuffer contains the last chunk
+ * of data from the underlying InputStream.
+ */
+ private boolean allInputConsumed = false;
+
+ /**
+ * Becomes true as soon as the decoder has been supplied with the
+ * last chunk of data from the InputStream after EOF has been
+ * reached. At this point, the last chunk of data has been drained
+ * from the byteBuffer.
+ */
+ private boolean decodingFinished = false;
+
+ /**
+ * Becomes true as soon as the decoder has been flushed. At this
+ * point, the last chunk of character data has been written to the
+ * charBuffer.
+ */
+ private boolean flushed = false;
+
+ /**
+ * Stores all registered MalformedInputListeners.
+ */
+ private Set listeners = new LinkedHashSet();
+
+ /**
+ * Initializes a new instance for reading from the given
+ * InputStream using the default encoding. The default encoding is
+ * currently determined by looking at the system property
+ * <code>file.encoding</code>. If this property isn't set,
+ * <code>ISO-8859-1</code> is used as a fallback.
+ *
+ * <p>This method should use {@link Charset.defaultCharset()}
+ * instead, but this isn't implemented in Classpath at the
+ * moment.</p>
+ *
+ * @param in the <code>InputStream</code> to read from.
+ */
+ public NotifyingInputStreamReader(InputStream in)
+ {
+ this(in, System.getProperty("file.encoding", "ISO-8859-1"));
+ }
+
+ /**
+ * Initializes a new instance for reading from the given
+ * InputStream using the specified charset.
+ *
+ * @param in the <code>InputStream</code> to read from.
+ * @param charsetName the canonical name or an alias of a
+ * <code>Charset</code>.
+ *
+ * @throws IllegalCharsetNameException if there is no
+ * <code>Charset</code> with the given canonical name or alias.
+ *
+ * @throws UnsupportedCharsetException if there is no support for
+ * the specified <code>Charset</code> in the runtime environment.
+ */
+ public NotifyingInputStreamReader(InputStream in, String charsetName)
+ throws IllegalCharsetNameException, UnsupportedCharsetException
+ {
+ this(in, Charset.forName(charsetName));
+ }
+
+ /**
+ * Initializes a new instance for reading from the given
+ * InputStream using the specified charset.
+ *
+ * @param in the <code>InputStream</code> to read from.
+ * @param charset the <code>Charset</code> to use for decoding
+ * characters.
+ */
+ public NotifyingInputStreamReader(InputStream in, Charset charset)
+ {
+ this(in, charset.newDecoder());
+ }
+
+ /**
+ * Initializes a new instance for reading from the given
+ * InputStream using the specified charset decoder.
+ *
+ * <strong>Note:</strong> the
+ * <code>NotifyingInputStreamReader</code> will not exhibit the
+ * advertised behaviour if you changed the action to take on
+ * malformed input in the specified
+ * <code>CharsetDecoder</code>. In other words, you should not
+ * call {@link CharsetDecoder.onMalformedInput(CodingErrorAction)}
+ * on the specified decoder before or while this reader is being
+ * used unless you know what you're doing.
+ *
+ * @param in the <code>InputStream</code> to read from.
+ * @param charset the <code>CharsetDecoder</code> to use for
+ * decoding characters.
+ */
+ public NotifyingInputStreamReader(InputStream in, CharsetDecoder decoder)
+ {
+ this.in = in;
+ this.decoder = decoder;
+ this.charBuffer = CharBuffer.wrap(new char[DEFAULT_INPUT_BUFFER_SIZE]);
+ this.charBuffer.position(charBuffer.limit());
+ this.readBuffer = new byte[DEFAULT_OUTPUT_BUFFER_SIZE];
+ this.byteBuffer = ByteBuffer.wrap(readBuffer);
+ this.byteBuffer.position(byteBuffer.limit());
+ }
+
+ public void close()
+ throws IOException
+ {
+ in.close();
+ }
+
+ /**
+ * Fill charBuffer with new character data. This method returns if
+ * either the charBuffer has been filled completely with decoded
+ * character data, or if EOF is reached in the underlying
+ * InputStream. When this method returns, charBuffer is flipped
+ * and ready to be read from.
+ */
+ private void fillCharBuf()
+ throws IOException
+ {
+ charBuffer.clear();
+ outer:
+ while (!flushed) {
+ CoderResult coderResult;
+ int charBufferPositionBefore = charBuffer.position();
+ if (!decodingFinished) {
+ coderResult = decoder.decode(byteBuffer, charBuffer, allInputConsumed);
+ if (allInputConsumed) {
+ decodingFinished = true;
+ }
+ }
+ else {
+ coderResult = decoder.flush(charBuffer);
+ flushed = coderResult.isUnderflow();
+ }
+
+ int charBufferPositionAfter = charBuffer.position();
+ for (int i=charBufferPositionBefore; i<charBufferPositionAfter; ++i) {
+ if (10 == charBuffer.get(i)) {
+ ++ lineNumber;
+ columnNumber = 0;
+ }
+ else {
+ ++ columnNumber;
+ }
+ }
+ if (coderResult.isOverflow()) {
+ break;
+ }
+ else if (coderResult.isUnderflow()) {
+ if (!allInputConsumed) {
+ int nRemainingBytes = 0;
+ if (byteBuffer.position() > 0) {
+ nRemainingBytes = Math.max(0, byteBuffer.limit() - byteBuffer.position());
+ }
+ if (nRemainingBytes > 0) {
+ byteBuffer.get(readBuffer, 0, nRemainingBytes);
+ }
+ byteBuffer.rewind();
+ int nread = in.read(readBuffer, nRemainingBytes,
+ readBuffer.length - nRemainingBytes);
+ if (nread < 0) {
+ allInputConsumed = true;
+ }
+ byteBuffer.limit(nRemainingBytes + Math.max(0, nread));
+ }
+ else {
+ break;
+ }
+ }
+ else if (coderResult.isMalformed()) {
+ fireMalformedInputEncountered(coderResult.length());
+ String replacement = decoder.replacement();
+ for (int i=0; i<coderResult.length(); ++i) {
+ if (charBuffer.remaining() > replacement.length()) {
+ charBuffer.put(replacement);
+ byteBuffer.position(byteBuffer.position() + 1);
+ columnNumber ++;
+ }
+ else {
+ break outer;
+ }
+ }
+ }
+ else if (coderResult.isUnmappable()) {
+ // This should not happen, since unmappable input bytes
+ // trigger a "malformed" event instead.
+ coderResult.throwException();
+ }
+ else {
+ // This should only happen if run in a future environment
+ // where additional events apart from underflow, overflow,
+ // malformed and unmappable can be generated.
+ coderResult.throwException();
+ }
+ }
+ charBuffer.flip();
+ }
+
+ /**
+ * Fire a MalformedInputEvent, notifying all registered listeners.
+ */
+ private void fireMalformedInputEncountered(int length)
+ {
+ MalformedInputEvent event
+ = new MalformedInputEvent(this, lineNumber, columnNumber, length);
+ Iterator it = listeners.iterator();
+ while (it.hasNext()) {
+ MalformedInputListener listener
+ = (MalformedInputListener)it.next();
+ listener.malformedInputEncountered(event);
+ }
+ }
+
+ public int read(char[] cbuf, int offset, int length)
+ throws IOException
+ {
+ if (flushed) {
+ return -1;
+ }
+ else {
+ int nread = 0;
+ while (nread < length && !flushed) {
+ while (charBuffer.hasRemaining() && nread < length) {
+ int copyLen = Math.min(length - nread,
+ charBuffer.remaining());
+ charBuffer.get(cbuf, offset + nread, copyLen);
+ nread += copyLen;
+ }
+ if (nread < length) {
+ fillCharBuf();
+ }
+ }
+ return nread;
+ }
+ }
+
+ public int read()
+ throws IOException
+ {
+ while (!flushed) {
+ if (charBuffer.hasRemaining()) {
+ return charBuffer.get();
+ }
+ else {
+ fillCharBuf();
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns whether this reader is ready. The reader is ready if
+ * there is data in the internal buffer, or if additional data can
+ * be read from the underlying InputStream.
+ */
+ public boolean ready()
+ {
+ return charBuffer.hasRemaining() || !flushed;
+ }
+
+ /**
+ * Register a <code>MalformedInputListener</code> which should be
+ * notified when malformed input is encountered.
+ */
+ public void addMalformedInputListener(MalformedInputListener listener)
+ {
+ this.listeners.add(listener);
+ }
+
+ /**
+ * Unregister a previously registered
+ * <code>MalformedInputListener</code> if it should no longer be
+ * notified when malformed input is encountered.
+ */
+ public void removeMalformedInputListener(MalformedInputListener listener)
+ {
+ this.listeners.remove(listener);
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/StringToolkit.java b/libjava/classpath/tools/gnu/classpath/tools/StringToolkit.java
new file mode 100644
index 000000000..dbb552707
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/StringToolkit.java
@@ -0,0 +1,84 @@
+/* gnu.classpath.tools.StringToolkit
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools;
+
+/**
+ * Provides various String-related helper methods.
+ *
+ * @author Julian Scheid
+ */
+public class StringToolkit
+{
+ /**
+ * Prevents instantiation.
+ */
+ private StringToolkit() {}
+
+ /**
+ * Return <code>haystack</code> with all occurrences of
+ * <code>needle</code> replaced by </code>replacement</code>.
+ *
+ * @param haystack the string to replace occurrences of <code>needle</code> in
+ * @param needle the substring to replace
+ * @param replacement the substring to replace <code>needle</code> with
+ *
+ * @return <code>haystack</code> with all occurrences of
+ * <code>needle</code> replaced by </code>replacement</code>.
+ */
+ public static String replace(String haystack, String needle, String replacement)
+ {
+ int ndx = haystack.indexOf(needle);
+ if (ndx < 0) {
+ return haystack;
+ }
+ else {
+ StringBuffer result = new StringBuffer();
+ result.append(haystack.substring(0, ndx));
+ result.append(replacement);
+ ndx += needle.length();
+ int ndx2;
+ while ((ndx2 = haystack.indexOf(needle, ndx)) >= 0) {
+ result.append(haystack.substring(ndx, ndx2));
+ result.append(replacement);
+ ndx = ndx2 + needle.length();
+ }
+ result.append(haystack.substring(ndx));
+ return result.toString();
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java
new file mode 100644
index 000000000..dfbedfe36
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java
@@ -0,0 +1,81 @@
+/* AppletClassLoader -- a loader for applet classes
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+
+public class AppletClassLoader extends URLClassLoader
+{
+ /**
+ * Constructs a new <code>AppletLoader</code> object.
+ *
+ * @param codebase the codebase of the applet
+ * @param archives the urls to add to the search path
+ */
+ public AppletClassLoader(URL codebase, ArrayList archives)
+ {
+ super(new URL[0]);
+
+ for (int count = 0; count < archives.size(); count++)
+ addURL((URL) archives.get(count));
+
+ addURL(codebase);
+ }
+
+ /**
+ * Finds the specified class. This method should be overridden by
+ * class loader implementations that follow the delegation model for
+ * loading classes, and will be invoked by the loadClass method after
+ * checking the parent class loader for the requested class. The default
+ * implementation throws a ClassNotFoundException.
+ *
+ * (description copied from java.lang.ClassLoader.findClass(String))
+ *
+ * @param name The name of the class.
+ *
+ * @return the resulting <code>Class</code> object.
+ *
+ * @exception ClassNotFoundException if the class is not found.
+ */
+ protected Class findClass(String name) throws ClassNotFoundException
+ {
+ return super.findClass(name);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java
new file mode 100644
index 000000000..6522a9ec1
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java
@@ -0,0 +1,95 @@
+/* AppletSecurityManager.java -- an applet security manager
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.io.FilePermission;
+import java.net.SocketPermission;
+import java.security.Permission;
+import java.security.SecurityPermission;
+import java.util.PropertyPermission;
+
+class AppletSecurityManager extends SecurityManager
+{
+ private boolean plugin;
+
+ AppletSecurityManager(boolean plugin)
+ {
+ this.plugin = plugin;
+ }
+
+ public void checkPermission(Permission permission)
+ {
+ if (permission == null)
+ throw new NullPointerException();
+
+ // FIXME: we need to restrict this.
+ //
+ // libgcj asks for "java.io.FilePermission <<ALL FILES>> execute"
+ // to be able to execute "addr2line" to get proper stack traces.
+ if (permission instanceof FilePermission)
+ return;
+
+ // FIXME: we need to restrict this.
+ if (permission instanceof SecurityPermission)
+ return;
+
+ // FIXME: is this really needed ?
+ if (permission instanceof PropertyPermission)
+ return;
+
+ // Needed to allow to access AWT event queue.
+ if (permission.getName().equals("accessEventQueue"))
+ return;
+
+ // Needed to create a class loader for each codebase.
+ if (permission.getName().equals("createClassLoader"))
+ return;
+
+ // FIXME: we need to allow access to codebase here.
+
+ if (permission instanceof SocketPermission // for net access
+ || permission instanceof RuntimePermission) // for checkWrite(FileDescriptor)
+ return;
+
+ if (! plugin && permission.getName().equals("exitVM"))
+ return;
+
+ // Reject all other permissions.
+ throw new SecurityException();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletTag.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletTag.java
new file mode 100644
index 000000000..d3910a2a6
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/AppletTag.java
@@ -0,0 +1,489 @@
+/* AppletTag.java -- a representation of an HTML APPLET tag
+ Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import gnu.xml.dom.html2.DomHTMLAppletElement;
+import gnu.xml.dom.html2.DomHTMLEmbedElement;
+import gnu.xml.dom.html2.DomHTMLObjectElement;
+
+import java.awt.Dimension;
+import java.awt.Toolkit;
+
+import java.io.File;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+
+/**
+ * @author Lillian Angel (langel@redhat.com)
+ * @author Thomas Fitzsimmons (fitzsim@redhat.com)
+ */
+class AppletTag
+{
+
+ /**
+ * The document base of this applet.
+ */
+ URL documentbase;
+
+ /**
+ * name of applet tag.
+ */
+ String name = "";
+
+ /**
+ * code of applet tag.
+ */
+ String code = "";
+
+ /**
+ * codebase of applet tag.
+ */
+ String codebase = "";
+
+ /**
+ * The archives.
+ */
+ ArrayList archives = new ArrayList();
+
+ /**
+ * The parameters.
+ */
+ HashMap parameters = new HashMap();
+
+ /**
+ * The screen size.
+ */
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+
+ /**
+ * Default constructor.
+ */
+ AppletTag()
+ {
+ // Do nothing.
+ }
+
+ /**
+ * Constructs an AppletTag and parses the given applet element.
+ *
+ * @param appElement - the Applet element to parse.
+ */
+ AppletTag(DomHTMLAppletElement appElement)
+ {
+ name = appElement.getName();
+ parameters.put("name", name);
+
+ parameters.put("object", appElement.getObject());
+ parameters.put("align", appElement.getAlign());
+ parameters.put("alt", appElement.getAlt());
+ parameters.put("height", appElement.getHeight());
+ parameters.put("hspace", Integer.toString(appElement.getHspace()));
+ parameters.put("vspace", Integer.toString(appElement.getVspace()));
+ parameters.put("width", appElement.getWidth());
+
+ TagParser.parseParams(appElement, this);
+
+ if (code.equals(""))
+ {
+ code = appElement.getCode();
+ if (code.equals(""))
+ code = appElement.getCls();
+ }
+
+ // Must initialize codebase before archives
+ if (codebase.equals(""))
+ {
+ codebase = appElement.getCodeBase();
+ if (codebase.equals(""))
+ codebase = appElement.getSrc();
+ }
+
+ if (archives.size() == 0)
+ {
+ String arcs = "";
+ String arch = appElement.getArchive();
+
+ if (code.indexOf(".") < 0)
+ arcs = code + ".jar";
+
+ if (!arch.equals(""))
+ arcs += "," + arch;
+
+ if (!arcs.equals(""))
+ archives = TagParser.parseArchives(arcs, this);
+ }
+ }
+
+ /**
+ * Constructs an AppletTag and parses the given embed element.
+ *
+ * @param embElement - the Embed element to parse.
+ */
+ AppletTag(DomHTMLEmbedElement embElement)
+ {
+ // In an EMBED tag, a parameter is any non-standard attribute. This
+ // is a problem for applets that take parameters named "code",
+ // "codebase", "archive", "object", or "type". The solution is to
+ // allow the same attributes, prefixed by "java_". The presence of
+ // a "java_" attribute indicates that the non-prefixed attribute
+ // should be interpreted as a parameter. For example if "java_code"
+ // and "code" attributes are present in the EMBED tag then the
+ // "code" attribute is interpreted as a parameter.
+
+ name = embElement.getName();
+ parameters.put("name", name);
+
+ String jobj = embElement.getJavaObject();
+ if (!jobj.equals(""))
+ parameters.put("java_object", jobj);
+ else
+ parameters.put("object", embElement.getObject());
+
+ parameters.put("width", embElement.getWidth());
+ parameters.put("height", embElement.getHeight());
+ parameters.put("align", embElement.getAlign());
+ parameters.put("alt", embElement.getAlt());
+ parameters.put("hspace", Integer.toString(embElement.getHspace()));
+ parameters.put("mayscript", embElement.getMayscript());
+ parameters.put("pluginspage", embElement.getPluginsPage());
+ parameters.put("title", embElement.getTitle());
+ parameters.put("type", embElement.getType());
+ parameters.put("java_type", embElement.getJavaType());
+ parameters.put("vspace", Integer.toString(embElement.getVspace()));
+
+ TagParser.parseParams(embElement, this);
+
+ // Must initialize codebase before archives
+ if (codebase.equals(""))
+ {
+ String javacb = embElement.getJavaCodeBase();
+ if (!javacb.equals(""))
+ codebase = javacb;
+ else
+ codebase = embElement.getCodeBase();
+ }
+
+ if (code.equals(""))
+ {
+ String jcode = embElement.getJavaCode();
+ if (!jcode.equals(""))
+ code = jcode;
+ else
+ code = embElement.getCode();
+ }
+
+ if (archives.size() == 0)
+ {
+ String arcs = "";
+ String jarch = embElement.getJavaArchive();
+ String arch = embElement.getArchive();
+
+ if (code.indexOf(".") < 0)
+ arcs = code + ".jar";
+
+ if (!jarch.equals(""))
+ arcs += "," + jarch;
+ else if (!arch.equals(""))
+ arcs += "," + arch;
+
+ if (!arcs.equals(""))
+ archives = TagParser.parseArchives(arcs, this);
+ }
+ }
+
+ /**
+ * Constructs an AppletTag and parses the given object element.
+ *
+ * @param objElement - the Object element to parse.
+ */
+ AppletTag(DomHTMLObjectElement objElement)
+ {
+ // In an OBJECT tag, a parameter is any non-standard attribute. This
+ // is a problem for applets that take parameters named "code",
+ // "codebase", "archive", "object", or "type". The solution is to
+ // allow the same attributes, prefixed by "java_". The presence of
+ // a "java_" attribute indicates that the non-prefixed attribute
+ // should be interpreted as a parameter. For example if "java_code"
+ // and "code" attributes are present in the OBJECT tag then the
+ // "code" attribute is interpreted as a parameter.
+
+ name = objElement.getName();
+ parameters.put("name", name);
+
+ String jobj = objElement.getJavaObject();
+ if (!jobj.equals(""))
+ parameters.put("java_object", jobj);
+ else
+ parameters.put("object", objElement.getObject());
+
+ parameters.put("type", objElement.getType());
+ parameters.put("java_type", objElement.getJavaType());
+ parameters.put("align", objElement.getAlign());
+ parameters.put("codetype", objElement.getCodeType());
+ parameters.put("data", objElement.getData());
+ parameters.put("declare", Boolean.toString(objElement.getDeclare()));
+ parameters.put("height", objElement.getHeight());
+ parameters.put("hspace", Integer.toString(objElement.getHspace()));
+ parameters.put("border", objElement.getBorder());
+ parameters.put("standby", objElement.getStandby());
+ parameters.put("tabindex", Integer.toString(objElement.getTabIndex()));
+ parameters.put("usemap", objElement.getUseMap());
+ parameters.put("vspace", Integer.toString(objElement.getVspace()));
+ parameters.put("width", objElement.getWidth());
+ parameters.put("mayscript", objElement.getMayscript());
+ parameters.put("scriptable", objElement.getScriptable());
+
+ TagParser.parseParams(objElement, this);
+
+ // Must initialize codebase before archives
+ if (codebase.equals(""))
+ {
+ String javacb = objElement.getJavaCodeBase();
+ if (! javacb.equals(""))
+ codebase = javacb;
+ else
+ codebase = objElement.getCodeBase();
+ }
+
+ if (code.equals(""))
+ {
+ String jcode = objElement.getJavaCode();
+ if (!jcode.equals(""))
+ code = jcode;
+ else
+ code = objElement.getCode();
+ }
+
+ if (archives.size() == 0)
+ {
+ String arcs = "";
+ String jarch = objElement.getJavaArchive();
+ String arch = objElement.getArchive();
+
+ if (code.indexOf(".") < 0)
+ arcs = code + ".jar";
+
+ if (!jarch.equals(""))
+ arcs += "," + jarch;
+ else if (!arch.equals(""))
+ arcs += "," + arch;
+
+ if (!arcs.equals(""))
+ archives = TagParser.parseArchives(arcs, this);
+ }
+ }
+
+ /**
+ * String representation of the tag.
+ *
+ * @return the string representation.
+ */
+ public String toString()
+ {
+ return (" name=" + name + "\n" + " code=" + code + "\n" + " codebase="
+ + codebase + "\n" + " archive=" + archives + "\n" + " parameters="
+ + parameters + "\n" + " documentbase=" + documentbase + "\n");
+ }
+
+ /**
+ * Returns the size of the applet.
+ *
+ * @return the size.
+ */
+ Dimension getSize()
+ {
+ Dimension size = new Dimension(320, 200);
+
+ try
+ {
+ String widthStr = (String) parameters.get("width");
+
+ if (widthStr != null && ! widthStr.equals(""))
+ {
+ if (widthStr.charAt(widthStr.length() - 1) == '%')
+ {
+ double p = NumberFormat.getPercentInstance(Locale.US).parse(widthStr).intValue() / 100.0;
+ size.width = (int)(p * screenSize.width);
+ }
+ else
+ size.width = NumberFormat.getInstance(Locale.US).parse(widthStr).intValue();
+ }
+ }
+ catch (ParseException e)
+ {
+ // Use default.
+ }
+
+ try
+ {
+ String heightStr = (String) parameters.get("height");
+
+ if (heightStr != null && !heightStr.equals(""))
+ {
+ if (heightStr.charAt(heightStr.length() - 1) == '%')
+ {
+ double p = NumberFormat.getPercentInstance(Locale.US).parse(heightStr).intValue() / 100.0;
+ size.height = (int) (p * screenSize.height);
+ }
+ else
+ size.height = NumberFormat.getInstance(Locale.US).parse(heightStr).intValue();
+ }
+ }
+ catch (ParseException e)
+ {
+ // Use default.
+ }
+
+ return size;
+ }
+
+ /**
+ * Gets the code base.
+ *
+ * @return the codebase.
+ */
+ String getCodeBase()
+ {
+ return codebase;
+ }
+
+ /**
+ * Gets the archive list.
+ *
+ * @return the archive list.
+ */
+ ArrayList getArchives()
+ {
+ return archives;
+ }
+
+ /**
+ * Gets the code.
+ *
+ * @return the code.
+ */
+ String getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Gets the document base.
+ *
+ * @return the document base.
+ */
+ URL getDocumentBase()
+ {
+ return documentbase;
+ }
+
+ /**
+ * Gets the specified parameter.
+ *
+ * @param name - the specified parameter.
+ * @return the parameter.
+ */
+ String getParameter(String name)
+ {
+ return (String) parameters.get(name.toLowerCase());
+ }
+
+ /**
+ * Prepends the base to the codebase.
+ *
+ * @return the new URL.
+ */
+ URL prependCodeBase(String base) throws MalformedURLException
+ {
+ if (documentbase == null)
+ documentbase = TagParser.db;
+
+ URL fullcodebase;
+
+ //If no codebase was specified, default to documentbase.
+ if (codebase.equals(""))
+ {
+ if (documentbase.getFile().endsWith(File.separator))
+ fullcodebase = documentbase;
+ else
+ {
+ String dirname = documentbase.getFile();
+ if (dirname.indexOf(".") < 0)
+ fullcodebase = new URL(documentbase + File.separator);
+ else
+ {
+ // Determine dirname for file by stripping everything
+ // past the last file separator.
+ dirname = dirname.substring(0,
+ dirname.lastIndexOf(File.separatorChar) + 1);
+
+ fullcodebase = new URL(documentbase.getProtocol(),
+ documentbase.getHost(),
+ documentbase.getPort(), dirname);
+ }
+ }
+ }
+ else
+ {
+ // codebase was specified.
+ URL codebaseURL = new URL(documentbase, codebase);
+
+ if ("file".equals(codebaseURL.getProtocol()))
+ {
+ if (new File(codebaseURL.getFile()).isDirectory() && !codebase.endsWith(File.separator))
+ fullcodebase = new URL(documentbase, codebase + File.separator);
+ else
+ fullcodebase = new URL(documentbase, codebase);
+ }
+ else if (codebase.endsWith(File.separator))
+ fullcodebase = new URL(documentbase, codebase);
+ else
+ fullcodebase = new URL(documentbase, codebase + File.separator);
+ }
+
+ return new URL(fullcodebase, base);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java
new file mode 100644
index 000000000..ebdd35922
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java
@@ -0,0 +1,133 @@
+/* CommonAppletContext.java -- a common applet's context
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.applet.Applet;
+import java.applet.AppletContext;
+import java.applet.AudioClip;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+
+/*
+ * CommonAppletContext represents the common context stuff for both
+ * types, plugins and standalone.
+ */
+abstract class CommonAppletContext
+ implements AppletContext
+{
+ // FIXME: this needs to be static, and we need one AppletContext per
+ // Applet.
+ List applets = new ArrayList();
+ HashMap streams = new HashMap();
+
+ void addApplet(Applet applet)
+ {
+ applets.add(applet);
+ }
+
+ ///////////////////////////////
+ //// AppletContext methods ////
+ ///////////////////////////////
+ public AudioClip getAudioClip(URL url)
+ {
+ return Applet.newAudioClip(url);
+ }
+
+ public Image getImage(URL url)
+ {
+ return Toolkit.getDefaultToolkit().getImage(url);
+ }
+
+ public Applet getApplet(String name)
+ {
+ Applet a;
+ String appletName;
+ Iterator i = applets.iterator();
+
+ while (i.hasNext())
+ {
+ a = (Applet) i.next();
+
+ appletName = a.getParameter("name");
+ if (a != null && appletName != null && appletName.equals(name))
+ return a;
+ }
+ return null;
+ }
+
+ public Enumeration getApplets()
+ {
+ return Collections.enumeration(applets);
+ }
+
+ public void showDocument(URL url)
+ {
+ showDocument(url, "_self");
+ }
+
+ /*
+ // FIXME: implement.
+ public abstract void showDocument (URL url, String target);
+
+ // FIXME: implement.
+ public abstract void showStatus (String status);
+ */
+ public void setStream(String key, InputStream stream)
+ {
+ streams.put(key, stream);
+ }
+
+ public InputStream getStream(String key)
+ {
+ return (InputStream) streams.get(key);
+ }
+
+ public Iterator getStreamKeys()
+ {
+ return streams.keySet().iterator();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java
new file mode 100644
index 000000000..bf14db573
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java
@@ -0,0 +1,139 @@
+/* CommonAppletStub.java -- an applet-browser interface class
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.applet.AppletContext;
+import java.applet.AppletStub;
+import java.applet.Applet;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+
+class CommonAppletStub
+ implements AppletStub
+{
+ private AppletTag tag;
+ private AppletContext context;
+ private Applet applet;
+
+ CommonAppletStub(AppletTag tag, AppletContext context, Applet applet)
+ {
+ this.tag = tag;
+ this.context = context;
+ this.applet = applet;
+ }
+
+ ////////////////////////////////
+ ////// AppletStub Methods //////
+ ////////////////////////////////
+
+ /**
+ * Tests whether or not this applet is currently active. An applet
+ * becomes active just before the browser invokes start (), and
+ * becomes inactive just before the browser invokes stop ().
+ *
+ * @return true if applet is active, false otherwise
+ */
+ public boolean isActive()
+ {
+ return true;
+ }
+
+ /**
+ * Returns the basename URL of the document in which this applet is
+ * embedded.
+ *
+ * @return the document base url.
+ */
+ public URL getDocumentBase()
+ {
+ return tag.getDocumentBase();
+ }
+
+ /**
+ * Returns the URL of the code base for this applet.
+ *
+ * @return the codebase url
+ */
+ public URL getCodeBase()
+ {
+ try
+ {
+ return tag.prependCodeBase("");
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException("Attempted to create"
+ + " invalid codebase URL.", e);
+ }
+ }
+
+ /**
+ * Returns the value of the specified parameter that was specified
+ * in the <code>APPLET</code> tag for this applet.
+ *
+ * @param name the key name
+ *
+ * @return the key value
+ */
+ public String getParameter(String name)
+ {
+ return tag.getParameter(name.toLowerCase());
+ }
+
+ /**
+ * Returns the applet context for this applet.
+ *
+ * @return the context
+ */
+ public AppletContext getAppletContext()
+ {
+ return context;
+ }
+
+ /**
+ * Requests that the applet window for this applet be resized.
+ *
+ * @param width the new witdh
+ * @param height the new height
+ */
+ public void appletResize(int width, int height)
+ {
+ applet.setBounds (0, 0, width, height);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java
new file mode 100644
index 000000000..059dbee40
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java
@@ -0,0 +1,53 @@
+/* ErrorApplet.java -- an applet to load in case of an error
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.applet.Applet;
+import java.awt.BorderLayout;
+import java.awt.Button;
+
+public class ErrorApplet extends Applet
+{
+ public ErrorApplet(String message)
+ {
+ setLayout(new BorderLayout());
+
+ Button button = new Button(message);
+ add(button);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/Main.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/Main.java
new file mode 100644
index 000000000..f6e02dbaa
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/Main.java
@@ -0,0 +1,323 @@
+/* Main.java -- a standalone viewer for Java applets
+ Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import java.applet.Applet;
+import java.awt.Dimension;
+import java.io.BufferedReader;
+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.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+
+class Main
+{
+ private static HashMap classLoaderCache = new HashMap();
+
+ private static ClassLoader getClassLoader(URL codebase, ArrayList archives)
+ {
+ // Should load class loader each time. It is possible that there
+ // are more than one applet to be loaded with different archives.
+ AppletClassLoader loader = new AppletClassLoader(codebase, archives);
+ classLoaderCache.put(codebase, loader);
+
+ return loader;
+ }
+
+ private static String code = null;
+ private static String codebase = null;
+ private static String archive = null;
+ private static List parameters = new ArrayList();
+ private static Dimension dimensions = new Dimension(-1, -1);
+ private static String pipeInName = null;
+ private static String pipeOutName = null;
+ private static boolean pluginMode = false;
+ private static Parser parser = null;
+
+ static Applet createApplet(AppletTag tag)
+ {
+ Applet applet = null;
+
+ try
+ {
+ ClassLoader loader = getClassLoader(tag.prependCodeBase(""),
+ tag.getArchives());
+ String code = tag.getCode();
+
+ if (code.endsWith(".class"))
+ code = code.substring(0, code.length() - 6).replace('/', '.');
+
+ Class c = loader.loadClass(code);
+ applet = (Applet) c.newInstance();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ if (applet == null)
+ applet = new ErrorApplet(Messages.getString ("Main.ErrorApplet"));
+
+ return applet;
+ }
+
+ protected static boolean verbose;
+
+ /**
+ * The main method starting the applet viewer.
+ *
+ * @param args the arguments given on the command line.
+ *
+ * @exception IOException if an error occurs.
+ */
+ public static void main(String[] args) throws IOException
+ {
+ parser = new ClasspathToolParser("appletviewer", true);
+ parser.setHeader(Messages.getString("Main.Usage"));
+
+ OptionGroup attributeGroup
+ = new OptionGroup(Messages.getString("Main.AppletTagOptions"));
+
+ attributeGroup.add(new Option("code",
+ Messages.getString("Main.CodeDescription"),
+ Messages.getString("Main.CodeArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ code = argument;
+ }
+ });
+ attributeGroup.add
+ (new Option("codebase",
+ Messages.getString("Main.CodebaseDescription"),
+ Messages.getString("Main.CodebaseArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ codebase = argument;
+ }
+ });
+ attributeGroup.add
+ (new Option("archive",
+ Messages.getString("Main.ArchiveDescription"),
+ Messages.getString("Main.ArchiveArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ archive = argument;
+ }
+ });
+ attributeGroup.add(new Option("width",
+ Messages.getString("Main.WidthDescription"),
+ Messages.getString("Main.WidthArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ dimensions.width = Integer.parseInt(argument);
+ }
+ });
+ attributeGroup.add(new Option("height",
+ Messages.getString("Main.HeightDescription"),
+ Messages.getString("Main.HeightArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ dimensions.height = Integer.parseInt(argument);
+ }
+ });
+ attributeGroup.add(new Option("param",
+ Messages.getString("Main.ParamDescription"),
+ Messages.getString("Main.ParamArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ parameters.add(argument);
+ }
+ });
+ OptionGroup pluginGroup
+ = new OptionGroup(Messages.getString("Main.PluginOption"));
+ pluginGroup.add(new Option("plugin",
+ Messages.getString("Main.PluginDescription"),
+ Messages.getString("Main.PluginArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ pluginMode = true;
+ int comma = argument.indexOf(',');
+ pipeInName = argument.substring(0, comma);
+ pipeOutName = argument.substring(comma + 1);
+ }
+ });
+ OptionGroup debuggingGroup
+ = new OptionGroup(Messages.getString("Main.DebuggingOption"));
+ debuggingGroup.add
+ (new Option("verbose",
+ Messages.getString("Main.VerboseDescription"),
+ (String) null)
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ OptionGroup compatibilityGroup
+ = new OptionGroup(Messages.getString("Main.CompatibilityOptions"));
+ compatibilityGroup.add
+ (new Option("debug",
+ Messages.getString("Main.DebugDescription"),
+ (String) null)
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ // Currently ignored.
+ }
+ });
+ compatibilityGroup.add
+ (new Option("encoding",
+ Messages.getString("Main.EncodingDescription"),
+ Messages.getString("Main.EncodingArgument"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ // FIXME: We should probably be using
+ // java.nio.charset.CharsetDecoder to handle the encoding. What
+ // is the status of Classpath's implementation?
+ }
+ });
+ parser.add(attributeGroup);
+ parser.add(pluginGroup);
+ parser.add(debuggingGroup);
+ parser.add(compatibilityGroup);
+
+ String[] urls = parser.parse(args);
+
+ // Print arguments.
+ printArguments(args);
+
+ args = urls;
+
+ if (dimensions.height < 0)
+ dimensions.height = 200;
+
+ if (dimensions.width < 0)
+ dimensions.width = (int) (1.6 * dimensions.height);
+
+ //System.setSecurityManager(new AppletSecurityManager(pluginMode));
+
+ if (pluginMode)
+ {
+ // Plugin will warn user about missing security manager.
+ InputStream in;
+ OutputStream out;
+
+ in = new FileInputStream(pipeInName);
+ out = new FileOutputStream(pipeOutName);
+
+ PluginAppletViewer.start(in, out);
+ }
+ else
+ {
+ // Warn user about missing security manager.
+ System.err.println(Messages.getString("Main.SecurityWarning") + "\n");
+
+ System.err.println(Messages.getString("Main.ContinuationPrompt"));
+
+ BufferedReader stdin
+ = new BufferedReader(new InputStreamReader(System.in));
+ String response = null;
+
+ try
+ {
+ response = stdin.readLine();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Failed to read response"
+ + " to continuation prompt.", e);
+ }
+
+ if (!(response.equals("c") || response.equals("C")))
+ {
+ System.exit(0);
+ }
+
+ if (code == null)
+ {
+ // The --code option wasn't given and there are no URL
+ // arguments so we have nothing to work with.
+ if (args.length == 0)
+ {
+ System.err.println(Messages.getString("Main.NoInputFiles"));
+ System.exit(1);
+ }
+ // Create a standalone appletviewer from a list of URLs.
+ new StandaloneAppletViewer(args);
+ }
+ else
+ {
+ // Create a standalone appletviewer from the --code
+ // option.
+ new StandaloneAppletViewer(code, codebase, archive,
+ parameters, dimensions);
+ }
+ }
+ }
+
+ static void printArguments(String[] args)
+ {
+ if (verbose)
+ {
+ System.out.println(Messages.getString("Main.RawArguments"));
+
+ for (int i = 0; i < args.length; i++)
+ System.out.println(" " + args[i]);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/Messages.java
new file mode 100644
index 000000000..614a509fd
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- localization support for appletviewer
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.appletviewer;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.appletviewer.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java
new file mode 100644
index 000000000..bc445a6b3
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java
@@ -0,0 +1,72 @@
+/* PluginAppletContext.java -- an applet's context within a web browser
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.net.URL;
+import java.io.IOException;
+
+/*
+ * PluginAppletContext represents the context within a webpage of a
+ * group of applets that all share the same codebase.
+ */
+class PluginAppletContext extends CommonAppletContext
+{
+ public void showDocument(URL url, String target)
+ {
+ try
+ {
+ PluginAppletViewer.write("url " + url + " " + target);
+ }
+ catch(IOException e)
+ {
+ throw new RuntimeException("showDocument failed.", e);
+ }
+ }
+
+ public void showStatus(String status)
+ {
+ try
+ {
+ PluginAppletViewer.write("status " + status);
+ }
+ catch(IOException e)
+ {
+ throw new RuntimeException("showStatus failed.", e);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java
new file mode 100644
index 000000000..da8399b6b
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java
@@ -0,0 +1,178 @@
+/* PluginAppletViewer.java -- manages embeddable applet windows
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.MalformedURLException;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+
+
+/**
+ * PluginAppletViewer communicates through pipes with a web browser
+ * plugin. A PluginAppletViewer manages applet windows that may be
+ * embedded into web pages.
+ */
+class PluginAppletViewer
+{
+ // A mapping of instance IDs to PluginAppletWindows.
+ static HashMap appletWindows = new HashMap ();
+
+ private static BufferedReader pluginInputStream;
+ private static BufferedWriter pluginOutputStream;
+
+ static void start(InputStream inputStream, OutputStream outputStream)
+ throws MalformedURLException, IOException
+ {
+ // Set up input and output pipes. Use UTF-8 encoding.
+ pluginInputStream =
+ new BufferedReader(new InputStreamReader(inputStream,
+ Charset.forName("UTF-8")));
+ pluginOutputStream =
+ new BufferedWriter(new OutputStreamWriter(outputStream,
+ Charset.forName("UTF-8")));
+
+ write("running");
+
+ // Read first message.
+ String message = read();
+
+ PluginAppletWindow currentWindow = null;
+
+ while (true)
+ {
+ if (message.startsWith("instance"))
+ {
+ // Read applet instance identifier.
+ String key = message.substring(9);
+
+ if (appletWindows.get(key) == null)
+ appletWindows.put(key, new PluginAppletWindow());
+
+ currentWindow = (PluginAppletWindow) appletWindows.get(key);
+ }
+ else if (message.startsWith("tag"))
+ {
+ int pos = message.indexOf(' ', 4);
+ String documentbase = message.substring(4, pos);
+ String tag = message.substring(pos + 1);
+ currentWindow.setParser(tag, documentbase);
+ }
+ else if (message.startsWith("handle"))
+ {
+ long handle = Long.parseLong(message.substring(7));
+
+ currentWindow.setHandle(handle);
+ }
+ else if (message.startsWith("width"))
+ {
+ int width = Integer.parseInt(message.substring(6));
+
+ currentWindow.setSize(width, currentWindow.getHeight());
+ }
+ else if (message.startsWith("height"))
+ {
+ int height = Integer.parseInt(message.substring(7));
+
+ currentWindow.setSize(currentWindow.getWidth(), height);
+ }
+ else if (message.startsWith("destroy"))
+ {
+ appletWindows.remove(currentWindow);
+ currentWindow.dispose();
+ }
+
+ // Read next message.
+ message = read();
+ }
+ }
+
+ /**
+ * Write string to plugin.
+ *
+ * @param message the message to write
+ *
+ * @exception IOException if an error occurs
+ */
+ static void write(String message) throws IOException
+ {
+ pluginOutputStream.write(message, 0, message.length());
+ pluginOutputStream.newLine();
+ pluginOutputStream.flush();
+
+ System.err.println
+ (" " + Messages.getString("PluginAppletViewer.AppletViewerWrote")
+ + message);
+ }
+
+ /**
+ * Read string from plugin.
+ *
+ * @return the read string
+ *
+ * @exception IOException if an error occurs
+ */
+ static String read() throws IOException
+ {
+ String message = pluginInputStream.readLine();
+
+ System.err.println
+ (" " + Messages.getString("PluginAppletViewer.AppletViewerRead")
+ + message);
+
+ if (message == null || message.equals("shutdown"))
+ {
+ // Close input/output channels to plugin.
+ pluginInputStream.close();
+ pluginOutputStream.close();
+
+ System.err.println
+ (Messages.getString("PluginAppletViewer.AppletViewerExiting"));
+
+ System.exit(0);
+ }
+
+ return message;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java
new file mode 100644
index 000000000..bc44a73d8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java
@@ -0,0 +1,448 @@
+/* PluginAppletWindow.java -- an embeddable applet window
+ Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import gnu.java.awt.EmbeddedWindow;
+
+import java.applet.Applet;
+import java.applet.AppletContext;
+import java.awt.Dimension;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
+import java.awt.event.HierarchyBoundsListener;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InputMethodListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+
+class PluginAppletWindow
+ extends EmbeddedWindow
+ implements ContainerListener, ComponentListener, MouseListener,
+ MouseMotionListener, InputMethodListener, HierarchyListener,
+ HierarchyBoundsListener
+{
+
+ // This class implements various listeners because the author of an applet
+ // may attach listeners to it, unaware of the applet's parent (this class).
+ // So, we must pass all listener events on this plugin applet window to the
+ // actual applet.
+
+ private static HashMap contexts = new HashMap();
+ private Applet applet;
+ private TagParser parser;
+ private AppletTag tag;
+
+ PluginAppletWindow()
+ {
+ super();
+ addContainerListener(this);
+ addComponentListener(this);
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addInputMethodListener(this);
+ addHierarchyListener(this);
+ addHierarchyBoundsListener(this);
+ }
+
+ ///////////////////////////////////
+ /// ContainerListener Methods /////
+ ///////////////////////////////////
+
+ /**
+ * This method is called when a component is added to the container.
+ *
+ * @param event the <code>ContainerEvent</code> indicating component
+ * addition
+ */
+ public void componentAdded(ContainerEvent event)
+ {
+ if (applet != null)
+ {
+ ContainerListener[] l = applet.getContainerListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentAdded(event);
+ }
+ }
+
+ /**
+ * This method is called when a component is removed from the container.
+ *
+ * @param event the <code>ContainerEvent</code> indicating component removal
+ */
+ public void componentRemoved(ContainerEvent event)
+ {
+ if (applet != null)
+ {
+ ContainerListener[] l = applet.getContainerListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentRemoved(event);
+ }
+ }
+
+ ///////////////////////////////////
+ /// ComponentListener Methods /////
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the component is resized.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the resize
+ */
+ public void componentResized(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentResized(event);
+ }
+ }
+
+ /**
+ * This method is called when the component is moved.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the move
+ */
+ public void componentMoved(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentMoved(event);
+ }
+ }
+
+ /**
+ * This method is called when the component is made visible.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the visibility
+ */
+ public void componentShown(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentShown(event);
+ }
+ }
+
+ /**
+ * This method is called when the component is hidden.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the visibility
+ */
+ public void componentHidden(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentHidden(event);
+ }
+ }
+
+ ///////////////////////////////////
+ ////// MouseListener Methods //////
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the mouse is clicked (pressed and released
+ * in short succession) on a component.
+ *
+ * @param event the <code>MouseEvent</code> indicating the click
+ */
+ public void mouseClicked(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseClicked(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse is pressed over a component.
+ *
+ * @param event the <code>MouseEvent</code> for the press
+ */
+ public void mousePressed(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mousePressed(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse is released over a component.
+ *
+ * @param event the <code>MouseEvent</code> for the release
+ */
+ public void mouseReleased(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseReleased(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse enters a component.
+ *
+ * @param event the <code>MouseEvent</code> for the entry
+ */
+ public void mouseEntered(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseEntered(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse exits a component.
+ *
+ * @param event the <code>MouseEvent</code> for the exit
+ */
+ public void mouseExited(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseExited(event);
+ }
+ }
+
+ ///////////////////////////////////
+ /// MouseMotionListener Methods ///
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the mouse is moved over a component
+ * while a button has been pressed.
+ *
+ * @param event the <code>MouseEvent</code> indicating the motion
+ */
+ public void mouseDragged(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseMotionListener[] l = applet.getMouseMotionListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseDragged(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse is moved over a component
+ * while no button is pressed.
+ *
+ * @param event the <code>MouseEvent</code> indicating the motion
+ */
+ public void mouseMoved(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseMotionListener[] l = applet.getMouseMotionListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseMoved(event);
+ }
+ }
+
+ ///////////////////////////////////
+ /// InputMethodListener Methods ///
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the text is changed.
+ *
+ * @param event the <code>InputMethodEvent</code> indicating the text change
+ */
+ public void inputMethodTextChanged(InputMethodEvent event)
+ {
+ if (applet != null)
+ {
+ InputMethodListener[] l = applet.getInputMethodListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].inputMethodTextChanged(event);
+ }
+ }
+
+ /**
+ * This method is called when the cursor position within the text is changed.
+ *
+ * @param event the <code>InputMethodEvent</code> indicating the change
+ */
+ public void caretPositionChanged(InputMethodEvent event)
+ {
+ if (applet != null)
+ {
+ InputMethodListener[] l = applet.getInputMethodListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].caretPositionChanged(event);
+ }
+ }
+
+ ///////////////////////////////////
+ //// HierarchyListener Methods ////
+ ///////////////////////////////////
+
+ /**
+ * Called when the hierarchy of this component changes. Use
+ * <code>getChangeFlags()</code> on the event to see what exactly changed.
+ *
+ * @param event the event describing the change
+ */
+ public void hierarchyChanged(HierarchyEvent event)
+ {
+ if (applet != null)
+ {
+ HierarchyListener[] l = applet.getHierarchyListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].hierarchyChanged(event);
+ }
+ }
+
+ /////////////////////////////////////////
+ //// HierarchyBoundsListener Methods ////
+ /////////////////////////////////////////
+
+ /**
+ * Called when an ancestor component of the source is moved.
+ *
+ * @param e the event describing the ancestor's motion
+ */
+ public void ancestorMoved(HierarchyEvent e)
+ {
+ if (applet != null)
+ {
+ HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].ancestorMoved(e);
+ }
+ }
+
+ /**
+ * Called when an ancestor component is resized.
+ *
+ * @param e the event describing the ancestor's resizing
+ */
+ public void ancestorResized(HierarchyEvent e)
+ {
+ if (applet != null)
+ {
+ HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].ancestorResized(e);
+ }
+ }
+
+ void setParser(String tag, String documentbase) throws MalformedURLException, IOException
+ {
+ URL documentbaseURL = TagParser.getLocationToURL(documentbase);
+ StringReader in = new StringReader(tag);
+ this.parser = new TagParser(in, documentbaseURL);
+ }
+
+ // /////////////////////////////////
+ // //// EmbeddedWindow Method //////
+ // /////////////////////////////////
+
+ /**
+ * Set the native handle of the window system to embed the window in.
+ *
+ * @param handle the native handle.
+ */
+ public void setHandle(long handle)
+ {
+ super.setHandle(handle);
+ addNotify();
+
+ ArrayList l = parser.parseAppletTags();
+ int s = l.size();
+
+ for (int i = 0; i < s; i++)
+ {
+ tag = (AppletTag) l.get(i);
+ applet = Main.createApplet(tag);
+
+ if (contexts.get(tag.getCodeBase()) == null)
+ contexts.put(tag.getCodeBase(), new PluginAppletContext());
+
+ add(applet);
+
+ AppletContext context = (AppletContext) contexts.get(tag.getCodeBase());
+ ((PluginAppletContext) context).addApplet(applet);
+
+ applet.setStub(new CommonAppletStub(tag, context, applet));
+ Dimension size = getSize();
+ if (size.width == 0 || size.height == 0)
+ size = tag.getSize();
+ applet.setSize(size);
+
+ // Initialize the applet before showing this window so that
+ // the applet doesn't receive events before it has been
+ // initialized.
+ applet.init();
+ applet.start();
+ setVisible(true);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java
new file mode 100644
index 000000000..48468f84d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java
@@ -0,0 +1,76 @@
+/* StandaloneAppletContext.java -- an applet's context within the
+ standalone viewer
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * StandaloneAppletContext represents the context within a webpage of a
+ * group of applets that all share the same codebase.
+ */
+class StandaloneAppletContext extends CommonAppletContext
+{
+ private List appletWindows;
+
+ StandaloneAppletContext(List appletWindows)
+ {
+ this.appletWindows = appletWindows;
+ }
+
+ public void showDocument(URL url, String target)
+ {
+ System.err.println
+ (Messages.getString("StandaloneAppletContext.ShowDocumentError"));
+ }
+
+ // In standalone mode, there are potentially several windows, each
+ // with its own status bar. In plugin mode, all the applets in the
+ // same context (on the same page) share the browser's status bar.
+ // The best way to simulate the plugin mode behaviour in standalone
+ // mode is to show the same status on each window's status bar.
+ public void showStatus(String status)
+ {
+ Iterator window = appletWindows.iterator();
+ while (window.hasNext())
+ ((StandaloneAppletWindow) window.next()).showStatus(status);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java
new file mode 100644
index 000000000..a59b03bfd
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java
@@ -0,0 +1,148 @@
+/* StandaloneAppletViewer.java -- a standalone viewer for Java applets
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.awt.Dimension;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+
+/**
+ * StandaloneAppletViewer displays an applet in its own Frame. Most
+ * of the context that is available to an applet within a webpage is
+ * available to it in StandaloneAppletViewer.
+ */
+class StandaloneAppletViewer extends Main
+{
+ static ArrayList appletTags = new ArrayList();
+ static ArrayList appletWindows = new ArrayList();
+
+ StandaloneAppletViewer(String[] urls)
+ throws MalformedURLException, IOException
+ {
+ // Handle each file specified on the command line.
+ for (int i = 0; i < urls.length; i++)
+ {
+ TagParser parser = new TagParser(urls[i]);
+ appletTags.addAll(parser.parseAppletTags());
+ }
+
+ printTags();
+ createWindows();
+ }
+
+ StandaloneAppletViewer(String code, String codebase, String archives,
+ List parameters, Dimension dimensions)
+ throws IOException
+ {
+ if (!(code.equals("") || code.endsWith(".class")))
+ {
+ System.err.println
+ (Messages.getString("StandaloneAppletViewer.CodeOptionError"));
+ System.exit(1);
+ }
+
+ String tagString =
+ "<EMBED"
+ + " CODE=\"" + code + "\""
+ + " WIDTH=" + dimensions.width
+ + " HEIGHT=" + dimensions.height
+ + " CODEBASE=\"" + codebase + "\""
+ + " ARCHIVE=\"" + archives + "\">";
+
+ // Handle parameters.
+ Iterator pairs = parameters.iterator();
+ while (pairs.hasNext())
+ {
+ StringTokenizer paramTokenizer =
+ new StringTokenizer((String) pairs.next(), ",");
+ tagString +=
+ "<PARAM NAME=" + paramTokenizer.nextToken().trim() + " VALUE="
+ + paramTokenizer.nextToken().trim() + ">";
+ }
+
+ tagString += "</EMBED>";
+
+ StringReader reader = new StringReader(tagString);
+ String path = System.getProperty("user.dir") + File.separator;
+ TagParser parser = new TagParser(reader,
+ new URL("file", "", path));
+ appletTags.addAll(parser.parseAppletTags());
+
+ printTags();
+ createWindows();
+ }
+
+ void printTags()
+ {
+ if (verbose)
+ {
+ System.out.println
+ (Messages.getString("StandaloneAppletViewer.ParsedAppletTags"));
+
+ for (int i = 0; i < appletTags.size(); i++)
+ {
+ AppletTag tag = (AppletTag) appletTags.get(i);
+
+ System.out.println
+ (" " + Messages.getString("StandaloneAppletViewer.Tag")
+ + " " + i + ":");
+ System.out.println(tag);
+ }
+ }
+ }
+
+ void createWindows()
+ {
+ for (int i = 0; i < appletTags.size(); i++)
+ {
+ AppletTag tag = (AppletTag) appletTags.get(i);
+
+ // Create a StandaloneAppletWindow and add it to the
+ // appletWindows list.
+ new StandaloneAppletWindow(tag, appletWindows);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java
new file mode 100644
index 000000000..64d3007f3
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java
@@ -0,0 +1,560 @@
+/* StandaloneAppletWindow.java -- an applet frame
+ Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import java.applet.Applet;
+import java.applet.AppletContext;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Insets;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
+import java.awt.event.HierarchyBoundsListener;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.event.InputMethodEvent;
+import java.awt.event.InputMethodListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.HashMap;
+import java.util.List;
+
+class StandaloneAppletWindow
+ extends Frame
+ implements ActionListener, ContainerListener, ComponentListener,
+ MouseListener, MouseMotionListener, InputMethodListener, HierarchyListener,
+ HierarchyBoundsListener
+{
+
+ // This class implements various listeners because the author of an applet
+ // may attach listeners to it, unaware of the applet's parent (this class).
+ // So, we must pass all listener events on this plugin applet window to the
+ // actual applet.
+
+ private static int testWindowCount;
+ private static HashMap contexts = new HashMap();
+ private Applet applet;
+ private Label status = new Label();
+
+ private MenuItem restartItem;
+ private MenuItem reloadItem;
+ private MenuItem cancelItem;
+ private MenuItem saveItem;
+ private MenuItem startItem;
+ private MenuItem cloneItem;
+ private MenuItem tagItem;
+ private MenuItem infoItem;
+ private MenuItem editItem;
+ private MenuItem encodingItem;
+ private MenuItem printItem;
+ private MenuItem propertiesItem;
+ private MenuItem closeItem;
+ private MenuItem quitItem;
+
+ StandaloneAppletWindow(AppletTag tag, List appletWindows)
+ {
+ appletWindows.add(this);
+ applet = Main.createApplet(tag);
+
+ if (contexts.get(tag.codebase) == null)
+ contexts.put(tag.codebase, new StandaloneAppletContext(appletWindows));
+
+ setLayout(new BorderLayout());
+ add(applet, BorderLayout.CENTER);
+ add(status, BorderLayout.SOUTH);
+
+ addWindowListener(new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent event)
+ {
+ applet.stop();
+ StandaloneAppletWindow.this.hide();
+ System.exit(0);
+ }
+ });
+
+ addContainerListener(this);
+ addComponentListener(this);
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addInputMethodListener(this);
+ addHierarchyListener(this);
+ addHierarchyBoundsListener(this);
+
+ restartItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuRestart"));
+ restartItem.setEnabled(false);
+ restartItem.addActionListener(this);
+ reloadItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuReload"));
+ reloadItem.setEnabled(false);
+ reloadItem.addActionListener(this);
+ cancelItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuCancel"));
+ cancelItem.setEnabled(false);
+ cancelItem.addActionListener(this);
+ saveItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuSave"));
+ saveItem.setEnabled(false);
+ saveItem.addActionListener(this);
+ startItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuStart"));
+ startItem.setEnabled(false);
+ startItem.addActionListener(this);
+ cloneItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuClone"));
+ cloneItem.setEnabled(false);
+ cloneItem.addActionListener(this);
+ closeItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuClose"));
+ closeItem.setEnabled(false);
+ closeItem.addActionListener(this);
+ tagItem =
+ new MenuItem(Messages.getString("StandaloneAppletWindow.MenuTag"));
+ tagItem.setEnabled(false);
+ tagItem.addActionListener(this);
+ infoItem =
+ new MenuItem(Messages.getString("StandaloneAppletWindow.MenuInfo"));
+ infoItem.setEnabled(false);
+ infoItem.addActionListener(this);
+ editItem =
+ new MenuItem(Messages.getString("StandaloneAppletWindow.MenuEdit"));
+ editItem.setEnabled(false);
+ editItem.addActionListener(this);
+ editItem.setEnabled(false);
+ encodingItem =
+ new MenuItem(Messages.getString("StandaloneAppletWindow.MenuEncoding"));
+ encodingItem.setEnabled(false);
+ encodingItem.addActionListener(this);
+ printItem =
+ new MenuItem(Messages.getString("StandaloneAppletWindow.MenuPrint"));
+ printItem.setEnabled(false);
+ printItem.addActionListener(this);
+ propertiesItem =
+ new MenuItem(Messages.getString("StandaloneAppletWindow.MenuProperties"));
+ propertiesItem.setEnabled(false);
+ propertiesItem.addActionListener(this);
+ quitItem = new MenuItem(Messages.getString("StandaloneAppletWindow.MenuQuit"));
+ quitItem.addActionListener(this);
+
+ MenuBar menuBar = new MenuBar();
+ Menu menuApplet = new Menu(Messages.getString("StandaloneAppletWindow.MenuTitle"));
+ menuBar.add(menuApplet);
+ menuApplet.add(restartItem);
+ menuApplet.add(reloadItem);
+ menuApplet.add(cancelItem);
+ menuApplet.add(saveItem);
+ menuApplet.add(startItem);
+ menuApplet.add(cloneItem);
+ menuApplet.addSeparator();
+ menuApplet.add(tagItem);
+ menuApplet.add(infoItem);
+ menuApplet.add(editItem);
+ menuApplet.add(encodingItem);
+ menuApplet.addSeparator();
+ menuApplet.add(printItem);
+ menuApplet.addSeparator();
+ menuApplet.add(propertiesItem);
+ menuApplet.addSeparator();
+ menuApplet.add(closeItem);
+ menuApplet.add(quitItem);
+ setMenuBar(menuBar);
+ setTitle(Messages.getString("StandaloneAppletWindow.WindowTitle")
+ + " " + tag.code);
+
+ AppletContext context = (AppletContext) contexts.get(tag.codebase);
+ ((StandaloneAppletContext) context).addApplet(applet);
+
+ applet.setStub(new CommonAppletStub(tag, context, applet));
+
+ // Create the frame's peer. Otherwise getPreferredSize will read
+ // its insets as 0.
+ addNotify();
+ Insets i = getInsets();
+ Dimension size = tag.getSize();
+ setSize(i.left + size.width + i.right,
+ i.top + size.height + status.getPreferredSize().height
+ + i.bottom);
+ applet.setSize(size);
+
+ // Initialize the applet before showing this window so that the
+ // applet doesn't receive events before it has been initialized.
+ applet.init();
+ applet.start();
+ setVisible(true);
+ }
+
+ private void closeWindow()
+ {
+ applet.stop();
+ StandaloneAppletViewer.appletWindows.remove(this);
+ StandaloneAppletWindow.this.hide();
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if (e.getSource() == quitItem)
+ {
+ closeWindow();
+ System.exit(0);
+ }
+ else if (e.getSource() == closeItem)
+ {
+ // Close current window.
+ closeWindow();
+
+ // Exit if there are other windows left.
+ if (StandaloneAppletViewer.appletWindows.isEmpty())
+ System.exit(0);
+ }
+ }
+
+ void showStatus(String status)
+ {
+ this.status.setText(status);
+ }
+
+
+ ///////////////////////////////////
+ /// ContainerListener Methods /////
+ ///////////////////////////////////
+
+ /**
+ * This method is called when a component is added to the container.
+ *
+ * @param event the <code>ContainerEvent</code> indicating component
+ * addition
+ */
+ public void componentAdded(ContainerEvent event)
+ {
+ if (applet != null)
+ {
+ ContainerListener[] l = applet.getContainerListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentAdded(event);
+ }
+ }
+
+ /**
+ * This method is called when a component is removed from the container.
+ *
+ * @param event the <code>ContainerEvent</code> indicating component removal
+ */
+ public void componentRemoved(ContainerEvent event)
+ {
+ if (applet != null)
+ {
+ ContainerListener[] l = applet.getContainerListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentRemoved(event);
+ }
+ }
+
+ ///////////////////////////////////
+ /// ComponentListener Methods /////
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the component is resized.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the resize
+ */
+ public void componentResized(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentResized(event);
+ }
+ }
+
+ /**
+ * This method is called when the component is moved.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the move
+ */
+ public void componentMoved(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentMoved(event);
+ }
+ }
+
+ /**
+ * This method is called when the component is made visible.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the visibility
+ */
+ public void componentShown(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentShown(event);
+ }
+ }
+
+ /**
+ * This method is called when the component is hidden.
+ *
+ * @param event the <code>ComponentEvent</code> indicating the visibility
+ */
+ public void componentHidden(ComponentEvent event)
+ {
+ if (applet != null)
+ {
+ ComponentListener[] l = applet.getComponentListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].componentHidden(event);
+ }
+ }
+
+ ///////////////////////////////////
+ ////// MouseListener Methods //////
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the mouse is clicked (pressed and released
+ * in short succession) on a component.
+ *
+ * @param event the <code>MouseEvent</code> indicating the click
+ */
+ public void mouseClicked(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseClicked(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse is pressed over a component.
+ *
+ * @param event the <code>MouseEvent</code> for the press
+ */
+ public void mousePressed(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mousePressed(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse is released over a component.
+ *
+ * @param event the <code>MouseEvent</code> for the release
+ */
+ public void mouseReleased(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseReleased(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse enters a component.
+ *
+ * @param event the <code>MouseEvent</code> for the entry
+ */
+ public void mouseEntered(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseEntered(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse exits a component.
+ *
+ * @param event the <code>MouseEvent</code> for the exit
+ */
+ public void mouseExited(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseListener[] l = applet.getMouseListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseExited(event);
+ }
+ }
+
+ ///////////////////////////////////
+ /// MouseMotionListener Methods ///
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the mouse is moved over a component
+ * while a button has been pressed.
+ *
+ * @param event the <code>MouseEvent</code> indicating the motion
+ */
+ public void mouseDragged(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseMotionListener[] l = applet.getMouseMotionListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseDragged(event);
+ }
+ }
+
+ /**
+ * This method is called when the mouse is moved over a component
+ * while no button is pressed.
+ *
+ * @param event the <code>MouseEvent</code> indicating the motion
+ */
+ public void mouseMoved(MouseEvent event)
+ {
+ if (applet != null)
+ {
+ MouseMotionListener[] l = applet.getMouseMotionListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].mouseMoved(event);
+ }
+ }
+
+ ///////////////////////////////////
+ /// InputMethodListener Methods ///
+ ///////////////////////////////////
+
+ /**
+ * This method is called when the text is changed.
+ *
+ * @param event the <code>InputMethodEvent</code> indicating the text change
+ */
+ public void inputMethodTextChanged(InputMethodEvent event)
+ {
+ if (applet != null)
+ {
+ InputMethodListener[] l = applet.getInputMethodListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].inputMethodTextChanged(event);
+ }
+ }
+
+ /**
+ * This method is called when the cursor position within the text is changed.
+ *
+ * @param event the <code>InputMethodEvent</code> indicating the change
+ */
+ public void caretPositionChanged(InputMethodEvent event)
+ {
+ if (applet != null)
+ {
+ InputMethodListener[] l = applet.getInputMethodListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].caretPositionChanged(event);
+ }
+ }
+
+ ///////////////////////////////////
+ //// HierarchyListener Methods ////
+ ///////////////////////////////////
+
+ /**
+ * Called when the hierarchy of this component changes. Use
+ * <code>getChangeFlags()</code> on the event to see what exactly changed.
+ *
+ * @param event the event describing the change
+ */
+ public void hierarchyChanged(HierarchyEvent event)
+ {
+ if (applet != null)
+ {
+ HierarchyListener[] l = applet.getHierarchyListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].hierarchyChanged(event);
+ }
+ }
+
+ /////////////////////////////////////////
+ //// HierarchyBoundsListener Methods ////
+ /////////////////////////////////////////
+
+ /**
+ * Called when an ancestor component of the source is moved.
+ *
+ * @param e the event describing the ancestor's motion
+ */
+ public void ancestorMoved(HierarchyEvent e)
+ {
+ if (applet != null)
+ {
+ HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].ancestorMoved(e);
+ }
+ }
+
+ /**
+ * Called when an ancestor component is resized.
+ *
+ * @param e the event describing the ancestor's resizing
+ */
+ public void ancestorResized(HierarchyEvent e)
+ {
+ if (applet != null)
+ {
+ HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners();
+ for (int i = 0; i < l.length; i++)
+ l[i].ancestorResized(e);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java
new file mode 100644
index 000000000..711b26ee5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/appletviewer/TagParser.java
@@ -0,0 +1,356 @@
+/* TagParser.java -- a parser for applet tags
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.appletviewer;
+
+import gnu.javax.swing.text.html.parser.HTML_401F;
+
+import gnu.xml.dom.DomNode;
+import gnu.xml.dom.html2.DomHTMLAppletElement;
+import gnu.xml.dom.html2.DomHTMLDocument;
+import gnu.xml.dom.html2.DomHTMLEmbedElement;
+import gnu.xml.dom.html2.DomHTMLObjectElement;
+import gnu.xml.dom.html2.DomHTMLParamElement;
+import gnu.xml.dom.html2.DomHTMLParser;
+
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.w3c.dom.NodeList;
+
+
+public class TagParser
+{
+
+ /**
+ * Parsed document.
+ */
+ DomHTMLDocument document;
+
+ /**
+ * The document base of this applet.
+ */
+ URL documentbase;
+
+ /**
+ * The document base of all the applets.
+ */
+ static URL db;
+
+ /**
+ * The tags in the document.
+ */
+ Vector tags = new Vector();
+
+ /**
+ * Default constructor.
+ */
+ TagParser()
+ {
+ // Do nothing.
+ }
+
+ /**
+ * Constructs and parses document using the given location.
+ *
+ * @param location - location of applet
+ */
+ TagParser(String location) throws IOException
+ {
+ documentbase = getLocationToURL(location);
+ db = documentbase;
+ InputStreamReader in = new InputStreamReader(documentbase.openStream());
+ document = (DomHTMLDocument) (new DomHTMLParser(HTML_401F.getInstance()).parseDocument(in));
+ }
+
+ /**
+ * Constructs and parses document.
+ *
+ * @param in - Reader to parse document from.
+ * @param documentBase - the URL of the applet
+ * @throws IOException - is thrown if any IO error occurs.
+ */
+ TagParser(Reader in, URL documentBase) throws IOException
+ {
+ documentbase = documentBase;
+ db = documentbase;
+ document = (DomHTMLDocument) (new DomHTMLParser(HTML_401F.getInstance()).parseDocument(in));
+ }
+
+ /**
+ * Parses all applet tags in document.
+ *
+ * @return a list of AppletTag objects representing the applet tags
+ * in document
+ */
+ ArrayList parseAppletTags()
+ {
+ ArrayList allTags = new ArrayList();
+ if (document == null)
+ return null;
+
+ recurseDocument(document.getChildNodes());
+
+ int sz = tags.size();
+ for (int j = 0; j < sz; j++)
+ {
+ Object curr = tags.get(j);
+ // Order of checking is important here.
+ // Must check embed element before applet element
+ // because DomHTMLEmbedElement extends DomHTMLAppletElement
+ AppletTag a = null;
+ if (curr instanceof DomHTMLEmbedElement)
+ a = new AppletTag((DomHTMLEmbedElement) curr);
+ else if (curr instanceof DomHTMLAppletElement)
+ a = new AppletTag((DomHTMLAppletElement) curr);
+ else if (curr instanceof DomHTMLObjectElement)
+ a = new AppletTag((DomHTMLObjectElement) curr);
+ a.documentbase = documentbase;
+ allTags.add(a);
+ }
+
+ return allTags;
+ }
+
+ /**
+ * Recurses the document in search for the appropriate tags.
+ *
+ * @param list - the Node list.
+ */
+ private void recurseDocument(NodeList list)
+ {
+ // Recurse and store all APPLET, OBJECT and EMBED tags.
+ int length = list.getLength();
+ for (int i = 0; i < length; i++)
+ {
+ DomNode curr = (DomNode) list.item(i);
+ if ((curr instanceof DomHTMLEmbedElement) ||
+ (curr instanceof DomHTMLAppletElement) ||
+ (curr instanceof DomHTMLObjectElement))
+ tags.add(curr);
+ recurseDocument(curr.getChildNodes());
+ }
+ }
+
+ /**
+ * Parses the param elements for a given node.
+ *
+ * @param node - the node element to parse.
+ */
+ static void parseParams(DomNode node, AppletTag t)
+ {
+ boolean ja = false;
+ boolean jb = false;
+ boolean jc = false;
+ NodeList l = node.getChildNodes();
+ int size = l.getLength();
+
+ if (size != 0)
+ for (int i = 0; i < size; i++)
+ {
+ Object c = l.item(i);
+ if (! (c instanceof DomHTMLParamElement))
+ continue;
+ DomHTMLParamElement curr = (DomHTMLParamElement) c;
+ String key = curr.getName();
+ String val = curr.getValue();
+
+ if (key.equals("java_code"))
+ {
+ jc = true;
+ t.code = val;
+ }
+ else if (key.equals("java_codebase"))
+ {
+ jb = true;
+ t.codebase = val;
+ }
+ else if (!jc && key.equals("code"))
+ t.code = val;
+ else if (!jc && key.equals("classid"))
+ {
+ int x = val.indexOf(":");
+ if (x != -1)
+ val = val.substring(x + 1);
+ t.code = val;
+ }
+ else if (!jb && key.equals("codebase"))
+ t.codebase = val;
+ else if (key.equals("java_archive"))
+ {
+ ja = true;
+ t.archives = parseArchives(val, t);
+ val = t.archives.toString();
+ }
+ else if (!ja && key.equals("archive"))
+ {
+ t.archives = parseArchives(val, t);
+ val = t.archives.toString();
+ }
+ val = unescapeString(val);
+ t.parameters.put(key.toLowerCase(), val);
+ }
+ }
+
+ /**
+ * This method does the same thing as the g_strcompress function in glib.
+ *
+ * @param value
+ * @return value in its original one-byte equivalence.
+ */
+ private static String unescapeString(String value)
+ {
+ String unescVal = "";
+ for (int i = 0; i < value.length(); i++)
+ {
+ if (i == value.length() - 1)
+ {
+ unescVal = unescVal.concat(value.substring(i));
+ break;
+ }
+ if (value.charAt(i) == '\\')
+ {
+ switch (value.charAt(i + 1))
+ {
+ case 'b':
+ unescVal = unescVal.concat("\b");
+ break;
+ case 'f':
+ unescVal = unescVal.concat("\f");
+ break;
+ case 'n':
+ unescVal = unescVal.concat("\n");
+ break;
+ case 'r':
+ unescVal = unescVal.concat("\r");
+ break;
+ case 't':
+ unescVal = unescVal.concat("\t");
+ break;
+ case '\\':
+ unescVal = unescVal.concat("\\");
+ break;
+ case '\"':
+ unescVal = unescVal.concat("\"");
+ break;
+ default:
+ unescVal = unescVal.concat("\\");
+ unescVal = unescVal.concat(value.substring(i + 1, i + 2));
+ break;
+ }
+ i++;
+ }
+ else
+ unescVal = unescVal.concat(value.substring(i, i + 1));
+ }
+ return unescVal;
+ }
+
+ /**
+ * Parses the archive string and returns a list.
+ *
+ * @param arcs the list of archives (comma-separated) in a String.
+ */
+ static ArrayList parseArchives(String arcs, AppletTag t)
+ {
+ try
+ {
+ ArrayList list = new ArrayList();
+
+ StringTokenizer tagTokenizer = new StringTokenizer(arcs, ",");
+ while (tagTokenizer.hasMoreTokens())
+ list.add(t.prependCodeBase(tagTokenizer.nextToken().trim()));
+
+ return list;
+ }
+ catch (MalformedURLException e)
+ {
+ }
+ return null;
+ }
+
+ /**
+ * Gets the location to the URL, given a location.
+ *
+ * @param location - the given location.
+ * @return the URL.
+ */
+ static URL getLocationToURL(String location) throws IOException
+ {
+ URL tmpDocumentBase = null;
+
+ try
+ {
+ // Try parsing location as a URL.
+ tmpDocumentBase = new URL(location);
+
+ // If no file was specified in the URL the assume the user
+ // meant the root page.
+ String f = tmpDocumentBase.getFile();
+ if (f.indexOf(".") == -1 && !f.endsWith(File.separator))
+ if (new File(tmpDocumentBase.getFile()).isDirectory())
+ tmpDocumentBase = new URL(location.concat(File.separator));
+ }
+ catch (MalformedURLException e)
+ {
+ // location is not a URL. See if it is an HTML file.
+ String path;
+
+ if (location.startsWith(File.separator))
+ path = new File(location).getCanonicalPath();
+ else
+ path = new File(System.getProperty("user.dir") + File.separator
+ + location).getCanonicalPath();
+
+ tmpDocumentBase = new URL("file", "", path);
+
+ if (new File(tmpDocumentBase.getFile()).isDirectory())
+ tmpDocumentBase = new URL("file", "", path + File.separator);
+ }
+
+ return tmpDocumentBase;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/common/CallbackUtil.java b/libjava/classpath/tools/gnu/classpath/tools/common/CallbackUtil.java
new file mode 100644
index 000000000..838d7403a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/common/CallbackUtil.java
@@ -0,0 +1,145 @@
+/* CallbackUtil.java -- Callback related utilities
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.common;
+
+import gnu.javax.security.auth.callback.ConsoleCallbackHandler;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.CallbackHandler;
+
+/**
+ * A <i>Helper</i> class containing general purpose utlity methods dealing with
+ * callback handlers and their <i>Security Provider</i>.
+ */
+public abstract class CallbackUtil
+{
+ private static final Logger log = Logger.getLogger(CallbackUtil.class.getName());
+
+ // default 0-arguments constructor
+
+ // Class methods
+ // --------------------------------------------------------------------------
+
+ /**
+ * Return an implementation of the {@link CallbackHandler}, from any
+ * {@link Provider}, capable of handling callbacks through the <i>console</i>;
+ * i.e. <code>System.in</code> and <code>System.out</code>.
+ * <p>
+ * If no <i>Security Provider</i> for this type of callback was found, this
+ * method returns the default GNU implementation.
+ *
+ * @return a console {@link CallbackHandler} implementation.
+ */
+ public static final CallbackHandler getConsoleHandler()
+ {
+ CallbackHandler result = getHandler("Console");
+ if (result == null)
+ {
+ log.fine("No console callback handler found. Will use ours");
+ result = new ConsoleCallbackHandler();
+ }
+ return result;
+ }
+
+ /**
+ * Return a {@link CallbackHandler}, of a designated type, for interacting
+ * with the user.
+ * <p>
+ * This method first finds all currently installed <i>Security Providers</i>
+ * capable of providing such service and then in turn attempts to instantiate
+ * the handler from those providers. As soon as one provider returns a non-
+ * null instance of the callback handler, the search stops and that instance
+ * is returned.
+ *
+ * @return a {@link CallbackHandler} of the designated type, or
+ * <code>null</code> if no provider was found for theis type of
+ * callback.
+ */
+ private static final CallbackHandler getHandler(String handlerType)
+ {
+ log.entering(CallbackUtil.class.getName(), "getHandler", handlerType);
+
+ CallbackHandler result = null;
+ String service = "CallbackHandler." + handlerType;
+ Provider[] providers = Security.getProviders(service);
+ if (providers != null)
+ for (int i = 0; i < providers.length; i++)
+ {
+ Provider p = providers[i];
+ String className = p.getProperty(service);
+ if (className != null)
+ try
+ {
+ result = (CallbackHandler) Class.forName(className.trim()).newInstance();
+ }
+ catch (InstantiationException x)
+ {
+ log.fine("InstantiationException while creating ["
+ + className + "] from provider [" + p.getName()
+ + "]. Ignore");
+ }
+ catch (IllegalAccessException x)
+ {
+ log.fine("IllegalAccessException while creating ["
+ + className + "] from provider [" + p.getName()
+ + "]. Ignore");
+ }
+ catch (ClassNotFoundException x)
+ {
+ log.fine("ClassNotFoundException while creating ["
+ + className + "] from provider [" + p.getName()
+ + "]. Ignore");
+ }
+
+ if (result != null)
+ {
+
+ log.fine("Will use [" + result.getClass().getName()
+ + "] from [" + p.getName() + "]");
+ break;
+ }
+ }
+
+ log.exiting(CallbackUtil.class.getName(), "getHandler", result);
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/common/ClasspathToolParser.java b/libjava/classpath/tools/gnu/classpath/tools/common/ClasspathToolParser.java
new file mode 100644
index 000000000..d740646e5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/common/ClasspathToolParser.java
@@ -0,0 +1,239 @@
+/* ClasspathToolParser.java -- Parser subclass for classpath tools
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.common;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.Reader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+/**
+ * This is like the Parser class, but is specialized for use by
+ * tools distributed with GNU Classpath. In particular it automatically
+ * computes the version string using the program's name.
+ */
+public class ClasspathToolParser
+ extends Parser
+{
+ private static String getVersionString(String programName)
+ {
+ String fmt = (Messages.getString("ClasspathToolParser.VersionFormat")); //$NON-NLS-1$
+ return MessageFormat.format(fmt,
+ new Object[]
+ {
+ programName,
+ Configuration.CLASSPATH_VERSION
+ });
+ }
+
+ public ClasspathToolParser(String programName)
+ {
+ this(programName, false);
+ }
+
+ public ClasspathToolParser(String programName, boolean longOnly)
+ {
+ super(programName, getVersionString(programName), longOnly);
+ addFinal(new Option('J',
+ Messages.getString("ClasspathToolParser.JArgument"),//$NON-NLS-1$
+ Messages.getString("ClasspathToolParser.JName"), //$NON-NLS-1$
+ true)
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ // -J should be handled by the wrapper binary.
+ // We add it here so that it shows up in the --help output.
+ }
+ });
+ }
+
+ public void parse(String[] inArgs, FileArgumentCallback files,
+ boolean handleFileLists)
+ {
+ FileArgumentCallback cb;
+
+ if (handleFileLists)
+ cb = new AtFileArgumentCallback(files);
+ else
+ cb = files;
+
+ parse(inArgs, cb);
+ }
+
+ public String[] parse(String[] inArgs, boolean handleFileLists)
+ {
+ final ArrayList<String> fileResult = new ArrayList<String>();
+
+ final FileArgumentCallback cb = new FileArgumentCallback()
+ {
+ public void notifyFile(String fileArgument)
+ {
+ fileResult.add(fileArgument);
+ }
+ };
+
+ if (handleFileLists)
+ parse(inArgs, new AtFileArgumentCallback(cb));
+ else
+ parse(inArgs, cb);
+
+ return fileResult.toArray(new String[fileResult.size()]);
+ }
+
+
+ /**
+ * Simple function that takes the given {@link Reader}, treats it like
+ * a textfile and reads all the whitespace separated entries from it
+ * and adds them to the @{link FileArgumentCallback} instance.
+ *
+ * @param reader the reader to read from.
+ * @param cb the callback to post the filenames to.
+ * @throws OptionException if an error occurs reading the list.
+ */
+ public void parseFileList(Reader reader, FileArgumentCallback cb)
+ throws OptionException
+ {
+ BufferedReader breader = new BufferedReader(reader);
+ String line = null;
+
+ try
+ {
+ while ((line = breader.readLine()) != null)
+ parseLine(line, cb);
+
+ reader.close();
+ }
+ catch (IOException ioe)
+ {
+ throw new OptionException("I/O error while reading a file list", ioe);
+ }
+
+ }
+
+ /**
+ * Parses whitespace separated file entries.
+ *
+ * Note: This is not coping with whitespace in files or quoting.
+ *
+ * @param line the line of the file to parse.
+ * @param cb the callback to pass the parsed file to.
+ * @throws IOException if an I/O error occurs.
+ * @throws OptionException if an error occurs in the callback.
+ */
+ private void parseLine(String line, FileArgumentCallback cb)
+ throws IOException, OptionException
+ {
+ final int length = line.length();
+ int start = 0;
+ int end = 0;
+
+ // While not reached end of line ...
+ while (start < length)
+ {
+ // Search for first non-whitespace character for the start of a word.
+ while (Character.isWhitespace(line.codePointAt(start)))
+ {
+ start++;
+
+ if (start == length)
+ return;
+ }
+
+ end = start + 1;
+
+ // Search for first whitespace character for the end of a word.
+ while (end < length && !Character.isWhitespace(line.codePointAt(end)))
+ end++;
+
+ cb.notifyFile(line.substring(start, end));
+
+ start = end + 1;
+ }
+ }
+
+ /**
+ * Implementation of {@link FileArgumentCallback} that handles
+ * file arguments in {@link #notifyFile} starting with a <code>@</code>
+ * through {@link ClasspathToolParser#parseFileList}.
+ */
+ class AtFileArgumentCallback extends FileArgumentCallback
+ {
+ FileArgumentCallback cb;
+
+ AtFileArgumentCallback(FileArgumentCallback cb)
+ {
+ this.cb = cb;
+ }
+
+ @Override
+ public void notifyFile(String fileArgument)
+ throws OptionException
+ {
+ if (fileArgument.codePointAt(0) == '@')
+ {
+ FileReader fr = null;
+
+ try
+ {
+ fr = new FileReader(fileArgument.substring(1));
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw new OptionException("File not found: " + fileArgument.substring(1),
+ fnfe);
+ }
+
+ ClasspathToolParser.this.parseFileList(fr, cb);
+ }
+ else
+ cb.notifyFile(fileArgument);
+ }
+
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/common/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/common/Messages.java
new file mode 100644
index 000000000..1c92d348d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/common/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- i18n support for tools common code
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.common;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.common.Messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/common/Persistent.java b/libjava/classpath/tools/gnu/classpath/tools/common/Persistent.java
new file mode 100644
index 000000000..5c85c9072
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/common/Persistent.java
@@ -0,0 +1,87 @@
+/* PersistentBidiHasthable.java -- Constants for the persistent tables.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.common;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * The static fields, shared by the multiple classes, implementing the
+ * persistent work.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+public interface Persistent
+{
+ /**
+ * Sheduled termination task.
+ */
+ static class ExitTask extends TimerTask
+ {
+ public void run()
+ {
+ System.exit(0);
+ }
+ }
+
+ /**
+ * The timer, sheduling all disk database update events, shared by all
+ * instances.
+ */
+ static Timer timer = new Timer(true);
+
+ /**
+ * The longest time, in ms, after that the database content on the disk must
+ * be updated. The algorithm is written to avoid the very frequent writings to
+ * the disk.
+ */
+ static long SAVE_AT_MOST_AFTER = 5000;
+
+ /**
+ * States how long the database may stay not updated during the intensive
+ * operations, in ms. Otherwise the intensively used structure may never
+ * be stored to the disk.
+ */
+ static long ALWAYS_UPDATE = 300000;
+
+ /**
+ * Write the database content to the disk.
+ */
+ void writeContent();
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/common/ProviderUtil.java b/libjava/classpath/tools/gnu/classpath/tools/common/ProviderUtil.java
new file mode 100644
index 000000000..bc6d93146
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/common/ProviderUtil.java
@@ -0,0 +1,163 @@
+/* ProviderUtil.java -- Security Provider related utilities
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.common;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Security;
+import java.util.logging.Logger;
+
+/**
+ * A <i>Helper</i> class containing general purpose utlity methods dealing with
+ * installing and removing <i>Security Providers</i> at runtime.
+ */
+public abstract class ProviderUtil
+{
+ private static final Logger log = Logger.getLogger(ProviderUtil.class.getName());
+
+ // default 0-arguments constructor
+
+ // Class methods
+ // --------------------------------------------------------------------------
+
+ /**
+ * Attempt to (a) instantiate, and (b) add a designated {@link Provider} by
+ * inserting at at the top of the list of <i>Security Providers</i> already
+ * present at runtime, only if it is not already installed.
+ * <p>
+ * <b>IMPORTANT</b>: This method overrides the security check usually carried
+ * out by the security manager when inserting a new {@link Provider}.
+ *
+ * @param providerClass a fully qualified, non-null, class name of a
+ * <i>Security Provider</i> to add if it is not already installed.
+ * @return an instance of {@link SecurityProviderInfo} referencing the
+ * {@link Provider} instance created with the designated class name,
+ * and its position in the underlying JVM runtime.
+ */
+ public static final SecurityProviderInfo addProvider(String providerClass)
+ {
+ log.entering(ProviderUtil.class.getName(), "addProvider", providerClass);
+
+ Provider provider = null;
+ try
+ {
+ provider = (Provider) Class.forName(providerClass.trim()).newInstance();
+ }
+ catch (InstantiationException x)
+ {
+ log.fine("InstantiationException while creating [" + providerClass
+ + "]. Ignore");
+ }
+ catch (IllegalAccessException x)
+ {
+ log.fine("IllegalAccessException while creating [" + providerClass
+ + "]. Ignore");
+ }
+ catch (ClassNotFoundException x)
+ {
+ log.fine("ClassNotFoundException while creating [" + providerClass
+ + "]. Ignore");
+ }
+
+ int position = provider != null ? addProvider(provider) : -1;
+ SecurityProviderInfo result = new SecurityProviderInfo(provider, position);
+
+ log.exiting(ProviderUtil.class.getName(), "addProvider", result);
+ return result;
+ }
+
+ /**
+ * Attempt to add the designated {@link Provider} by inserting at at the top
+ * of the list of <i>Security Providers</i> already present at runtime, only
+ * if it is not already installed.
+ * <p>
+ * <b>IMPORTANT</b>: This method overrides the security check usually carried
+ * out by the security manager when inserting a new {@link Provider}.
+ *
+ * @param provider a non-null <i>Security Provider</i> to add if it is not
+ * already installed.
+ * @return the new position of the designated provider in the list if it was
+ * not already present, or <code>-1</code> if it was already
+ * installed.
+ */
+ public static final int addProvider(final Provider provider)
+ {
+ log.entering(ProviderUtil.class.getName(), "addProvider", provider);
+
+ Integer actualPosition = (Integer) AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ int result = Security.insertProviderAt(provider, 1);
+ return Integer.valueOf(result);
+ }
+ });
+
+ int result = actualPosition.intValue();
+ log.fine("Provider [" + provider.getName() + "] installed? " + (result != - 1));
+
+ log.exiting(ProviderUtil.class.getName(), "addProvider", actualPosition);
+ return result;
+ }
+
+ /**
+ * Remove a designated <i>Security Provider</i>.
+ * <p>
+ * <b>IMPORTANT</b>: This method overrides the security check usually carried
+ * out by the security manager when removing a {@link Provider}.
+ *
+ * @param providerName the name of the {@link Provider} to remove.
+ */
+ public static final void removeProvider(final String providerName)
+ {
+ log.entering(ProviderUtil.class.getName(), "removeProvider", providerName);
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ Security.removeProvider(providerName);
+ return null;
+ }
+ });
+
+ log.exiting(ProviderUtil.class.getName(), "removeProvider");
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/common/SecurityProviderInfo.java b/libjava/classpath/tools/gnu/classpath/tools/common/SecurityProviderInfo.java
new file mode 100644
index 000000000..44faebf76
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/common/SecurityProviderInfo.java
@@ -0,0 +1,99 @@
+/* SecurityProviderInfo.java -- Data Access Object for a security provider
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.common;
+
+import java.security.Provider;
+
+/**
+ * A Data Access Object (DAO) referenceing a <i>Security Provider</i> and its
+ * position in the list of installed <i>Security Providers</i> in the underlying
+ * JVM runtime.
+ */
+public class SecurityProviderInfo
+{
+ final private Provider provider;
+ final private int position;
+ private transient String str;
+
+ /**
+ * Constructs an instance of <code>SecurityProviderInfo</code>.
+ * <p>
+ * Used by {@link ProviderUtil} to indicate the result of adding a provider,
+ * given its class name.
+ *
+ * @param provider the possibly <code>null</code> {@link Provider}.
+ * @param position the position of <code>provider</code> in the list of
+ * <i>Security Providers</i> in the underlying JVM runtime. <code>-1</code>
+ * if that provider (a) is <code>null</code>, or (b) was not added because it
+ * was already there.
+ */
+ SecurityProviderInfo(Provider provider, int position)
+ {
+ super();
+
+ this.provider = provider;
+ this.position = position;
+ }
+
+ /** @return the possibly <code>null</code> {@link Provider} instance. */
+ public Provider getProvider()
+ {
+ return this.provider;
+ }
+
+ /**
+ * @return the position of the {@link Provider}, or <code>-1</code> if it
+ * was not added.
+ */
+ public int getPosition()
+ {
+ return this.position;
+ }
+
+ public String toString()
+ {
+ if (str == null)
+ if (provider == null)
+ str = "SecurityProviderInfo{null, -1}";
+ else
+ str = "SecurityProviderInfo{" + provider.getName() + ", " + position + "}";
+
+ return str;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/AbstractDoclet.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/AbstractDoclet.java
new file mode 100644
index 000000000..4369782f9
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/AbstractDoclet.java
@@ -0,0 +1,1386 @@
+/* gnu.classpath.tools.doclets.AbstractDoclet
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ConstructorDoc;
+import com.sun.javadoc.Doc;
+import com.sun.javadoc.Doclet;
+import com.sun.javadoc.ExecutableMemberDoc;
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.MethodDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.Parameter;
+import com.sun.javadoc.RootDoc;
+import com.sun.javadoc.Tag;
+import com.sun.javadoc.Type;
+
+import com.sun.tools.doclets.Taglet;
+
+import gnu.classpath.tools.taglets.GnuExtendedTaglet;
+import gnu.classpath.tools.taglets.AuthorTaglet;
+import gnu.classpath.tools.taglets.CodeTaglet;
+import gnu.classpath.tools.taglets.DeprecatedTaglet;
+import gnu.classpath.tools.taglets.GenericTaglet;
+import gnu.classpath.tools.taglets.SinceTaglet;
+import gnu.classpath.tools.taglets.ValueTaglet;
+import gnu.classpath.tools.taglets.VersionTaglet;
+import gnu.classpath.tools.taglets.TagletContext;
+
+import gnu.classpath.tools.IOToolkit;
+import gnu.classpath.tools.FileSystemClassLoader;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.InvocationTargetException;
+
+import java.text.MessageFormat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * An abstract Doclet implementation with helpers for common tasks
+ * performed by Doclets.
+ */
+public abstract class AbstractDoclet
+{
+ /**
+ * Mapping from tag type to Taglet for user Taglets specified on
+ * the command line.
+ */
+ protected Map tagletMap = new LinkedHashMap();
+
+ /**
+ * Stores the package groups specified in the user
+ * options. Contains objects of type PackageGroup.
+ */
+ private List packageGroups = new LinkedList();
+
+ /**
+ * The current classpath for loading taglet classes.
+ */
+ private String tagletPath;
+
+ /**
+ * Keeps track of the tags mentioned by the user during option
+ * processiong so that an error can be emitted if a tag is
+ * mentioned more than once.
+ */
+ private List mentionedTags = new LinkedList();
+
+ public static int optionLength(String option) {
+ return instance.getOptionLength(option);
+ }
+
+ public static boolean validOptions(String[][] options) {
+ return true;
+ }
+
+ private static AbstractDoclet instance;
+
+ protected static void setInstance(AbstractDoclet instance)
+ {
+ AbstractDoclet.instance = instance;
+ }
+
+ protected abstract void run()
+ throws DocletConfigurationException, IOException;
+
+ public static boolean start(RootDoc rootDoc)
+ {
+ try {
+
+ instance.startInstance(rootDoc);
+ return true;
+ }
+ catch (DocletConfigurationException e) {
+ instance.printError(e.getMessage());
+ return false;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ protected RootDoc getRootDoc()
+ {
+ return this.rootDoc;
+ }
+
+ private RootDoc rootDoc;
+
+ protected abstract InlineTagRenderer getInlineTagRenderer();
+
+ private void startInstance(RootDoc rootDoc)
+ throws DocletConfigurationException, IOException
+ {
+ this.rootDoc = rootDoc;
+
+ // Set the default Taglet order
+
+ registerTaglet(new VersionTaglet());
+ registerTaglet(new AuthorTaglet());
+ registerTaglet(new SinceTaglet(getInlineTagRenderer()));
+ registerTaglet(new StandardTaglet("serial"));
+ registerTaglet(new StandardTaglet("deprecated"));
+ registerTaglet(new StandardTaglet("see"));
+ registerTaglet(new StandardTaglet("param"));
+ registerTaglet(new StandardTaglet("return"));
+
+ registerTaglet(new ValueTaglet());
+ registerTaglet(new CodeTaglet());
+
+ // Process command line options
+
+ for (int i=0, ilim=rootDoc.options().length; i<ilim; ++i) {
+
+ String[] optionArr = rootDoc.options()[i];
+ String _optionTag = optionArr[0];
+
+ DocletOption option = (DocletOption)nameToOptionMap.get(_optionTag.toLowerCase());
+
+ if (null != option) {
+ option.set(optionArr);
+ }
+ }
+
+ // Enable/disable standard taglets based on user input
+
+ AuthorTaglet.setTagletEnabled(optionAuthor.getValue());
+ VersionTaglet.setTagletEnabled(optionVersion.getValue());
+ SinceTaglet.setTagletEnabled(!optionNoSince.getValue());
+ DeprecatedTaglet.setTagletEnabled(!optionNoDeprecated.getValue());
+
+ if (!getTargetDirectory().exists()) {
+ if (!getTargetDirectory().mkdirs()) {
+ throw new DocletConfigurationException("Cannot create target directory "
+ + getTargetDirectory());
+ }
+ }
+
+ run();
+ }
+
+ public File getTargetDirectory()
+ {
+ return optionTargetDirectory.getValue();
+ }
+
+ private DocletOptionFile optionTargetDirectory =
+ new DocletOptionFile("-d",
+ new File(System.getProperty("user.dir")));
+
+ private DocletOptionFlag optionNoEmailWarn =
+ new DocletOptionFlag("-noemailwarn");
+
+ private DocletOptionFlag optionAuthor =
+ new DocletOptionFlag("-author");
+
+ private DocletOptionFlag optionVersion =
+ new DocletOptionFlag("-version");
+
+ private DocletOptionFlag optionNoSince =
+ new DocletOptionFlag("-nosince");
+
+ private DocletOptionFlag optionNoDeprecated =
+ new DocletOptionFlag("-nodeprecated");
+
+ private DocletOptionGroup optionGroup =
+ new DocletOptionGroup("-group");
+
+ private DocletOptionPackageWildcard optionNoQualifier =
+ new DocletOptionPackageWildcard("-noqualifier", true);
+
+ private DocletOptionFlag optionDocFilesSubDirs =
+ new DocletOptionFlag("-docfilessubdirs");
+
+ private DocletOptionColonSeparated optionExcludeDocFilesSubDir =
+ new DocletOptionColonSeparated("-excludedocfilessubdir");
+
+ private DocletOptionTagletPath optionTagletPath =
+ new DocletOptionTagletPath("-tagletpath");
+
+ private DocletOptionTag optionTaglet =
+ new DocletOptionTag("-taglet");
+
+ private DocletOptionTag optionTag =
+ new DocletOptionTag("-tag");
+
+ private class DocletOptionTaglet
+ extends DocletOption
+ {
+ DocletOptionTaglet(String optionName)
+ {
+ super(optionName);
+ }
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+
+ boolean tagletLoaded = false;
+
+ String useTagletPath = AbstractDoclet.this.tagletPath;
+ if (null == useTagletPath) {
+ useTagletPath = System.getProperty("java.class.path");
+ }
+
+ try {
+ Class tagletClass;
+ try {
+ tagletClass
+ = new FileSystemClassLoader(useTagletPath).loadClass(optionArr[1]);
+ }
+ catch (ClassNotFoundException e) {
+ // If not found on specified tagletpath, try default classloader
+ tagletClass
+ = Class.forName(optionArr[1]);
+ }
+ Method registerTagletMethod
+ = tagletClass.getDeclaredMethod("register", new Class[] { java.util.Map.class });
+
+ if (!registerTagletMethod.getReturnType().equals(Void.TYPE)) {
+ printError("Taglet class '" + optionArr[1] + "' found, but register method doesn't return void.");
+ }
+ else if (registerTagletMethod.getExceptionTypes().length > 0) {
+ printError("Taglet class '" + optionArr[1] + "' found, but register method contains throws clause.");
+ }
+ else if ((registerTagletMethod.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC | Modifier.ABSTRACT)) != (Modifier.STATIC | Modifier.PUBLIC)) {
+ printError("Taglet class '" + optionArr[1] + "' found, but register method isn't public static, or is abstract..");
+ }
+ else {
+ Map tempMap = new HashMap();
+ registerTagletMethod.invoke(null, new Object[] { tempMap });
+ tagletLoaded = true;
+ String name = (String)tempMap.keySet().iterator().next();
+ Taglet taglet = (Taglet)tempMap.get(name);
+ tagletMap.put(name, taglet);
+ mentionedTags.add(taglet);
+ }
+ }
+ catch (NoSuchMethodException e) {
+ printError("Taglet class '" + optionArr[1] + "' found, but doesn't contain the register method.");
+ }
+ catch (SecurityException e) {
+ printError("Taglet class '" + optionArr[1] + "' cannot be loaded: " + e.getMessage());
+ }
+ catch (InvocationTargetException e) {
+ printError("Taglet class '" + optionArr[1] + "' found, but register method throws exception: " + e.toString());
+ }
+ catch (IllegalAccessException e) {
+ printError("Taglet class '" + optionArr[1] + "' found, but there was a problem when accessing the register method: " + e.toString());
+ }
+ catch (IllegalArgumentException e) {
+ printError("Taglet class '" + optionArr[1] + "' found, but there was a problem when accessing the register method: " + e.toString());
+ }
+ catch (ClassNotFoundException e) {
+ printError("Taglet class '" + optionArr[1] + "' cannot be found.");
+ }
+ return tagletLoaded;
+ }
+ }
+
+ private class DocletOptionGroup
+ extends DocletOption
+ {
+ DocletOptionGroup(String optionName)
+ {
+ super(optionName);
+ }
+
+ public int getLength()
+ {
+ return 3;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ try {
+ PackageMatcher packageMatcher = new PackageMatcher();
+
+ StringTokenizer tokenizer = new StringTokenizer(optionArr[2], ":");
+ while (tokenizer.hasMoreTokens()) {
+ String packageWildcard = tokenizer.nextToken();
+ packageMatcher.addWildcard(packageWildcard);
+ }
+
+ SortedSet groupPackages = packageMatcher.filter(rootDoc.specifiedPackages());
+
+ packageGroups.add(new PackageGroup(optionArr[1], groupPackages));
+
+ return true;
+ }
+ catch (InvalidPackageWildcardException e) {
+ return false;
+ }
+ }
+ }
+
+
+ private class DocletOptionTagletPath
+ extends DocletOption
+ {
+ DocletOptionTagletPath(String optionName)
+ {
+ super(optionName);
+ }
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ AbstractDoclet.this.tagletPath = optionArr[1];
+ return true;
+ }
+ }
+
+ private class DocletOptionTag
+ extends DocletOption
+ {
+ DocletOptionTag(String optionName)
+ {
+ super(optionName);
+ }
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ String tagSpec = optionArr[1];
+ boolean validTagSpec = false;
+ int ndx1 = tagSpec.indexOf(':');
+ if (ndx1 < 0) {
+ Taglet taglet = (Taglet)tagletMap.get(tagSpec);
+ if (null == taglet) {
+ printError("There is no standard tag '" + tagSpec + "'.");
+ }
+ else {
+ if (mentionedTags.contains(taglet)) {
+ printError("Tag '" + tagSpec + "' has been added or moved before.");
+ }
+ else {
+ mentionedTags.add(taglet);
+
+ // re-append taglet
+ tagletMap.remove(tagSpec);
+ tagletMap.put(tagSpec, taglet);
+ }
+ }
+ }
+ else {
+ int ndx2 = tagSpec.indexOf(':', ndx1 + 1);
+ if (ndx2 > ndx1 && ndx2 < tagSpec.length() - 1) {
+ String tagName = tagSpec.substring(0, ndx1);
+ String tagHead = null;
+ if (tagSpec.charAt(ndx2 + 1) == '\"') {
+ if (tagSpec.charAt(tagSpec.length() - 1) == '\"') {
+ tagHead = tagSpec.substring(ndx2 + 2, tagSpec.length() - 1);
+ validTagSpec = true;
+ }
+ }
+ else {
+ tagHead = tagSpec.substring(ndx2 + 1);
+ validTagSpec = true;
+ }
+
+ boolean tagScopeOverview = false;
+ boolean tagScopePackages = false;
+ boolean tagScopeTypes = false;
+ boolean tagScopeConstructors = false;
+ boolean tagScopeMethods = false;
+ boolean tagScopeFields = false;
+ boolean tagDisabled = false;
+
+ tag_option_loop:
+ for (int n=ndx1+1; n<ndx2; ++n) {
+ switch (tagSpec.charAt(n)) {
+ case 'X':
+ tagDisabled = true;
+ break;
+ case 'a':
+ tagScopeOverview = true;
+ tagScopePackages = true;
+ tagScopeTypes = true;
+ tagScopeConstructors = true;
+ tagScopeMethods = true;
+ tagScopeFields = true;
+ break;
+ case 'o':
+ tagScopeOverview = true;
+ break;
+ case 'p':
+ tagScopePackages = true;
+ break;
+ case 't':
+ tagScopeTypes = true;
+ break;
+ case 'c':
+ tagScopeConstructors = true;
+ break;
+ case 'm':
+ tagScopeMethods = true;
+ break;
+ case 'f':
+ tagScopeFields = true;
+ break;
+ default:
+ validTagSpec = false;
+ break tag_option_loop;
+ }
+ }
+
+ if (validTagSpec) {
+ GenericTaglet taglet
+ = new GenericTaglet(tagName,
+ tagHead,
+ tagScopeOverview,
+ tagScopePackages,
+ tagScopeTypes,
+ tagScopeConstructors,
+ tagScopeMethods,
+ tagScopeFields);
+ taglet.setTagletEnabled(!tagDisabled);
+ taglet.register(tagletMap);
+ mentionedTags.add(taglet);
+ }
+ }
+ }
+ if (!validTagSpec) {
+ printError("Value for option -tag must be in format \"<tagname>:Xaoptcmf:<taghead>\".");
+ }
+ return validTagSpec;
+ }
+ }
+
+ private DocletOption[] commonOptions =
+ {
+ optionTargetDirectory,
+ optionAuthor,
+ optionVersion,
+ optionNoSince,
+ optionNoDeprecated,
+ optionGroup,
+ optionDocFilesSubDirs,
+ optionExcludeDocFilesSubDir,
+ optionTagletPath,
+ optionTaglet,
+ optionTag,
+ };
+
+ private void registerOptions()
+ {
+ if (!optionsRegistered) {
+ for (int i=0; i<commonOptions.length; ++i) {
+ DocletOption option = commonOptions[i];
+ registerOption(option);
+ }
+ DocletOption[] docletOptions = getOptions();
+ for (int i=0; i<docletOptions.length; ++i) {
+ DocletOption option = docletOptions[i];
+ registerOption(option);
+ }
+ optionsRegistered = true;
+ }
+ }
+
+ protected abstract DocletOption[] getOptions();
+
+ private boolean optionsRegistered = false;
+
+ private void registerOption(DocletOption option)
+ {
+ nameToOptionMap.put(option.getName(), option);
+ }
+
+ private Map nameToOptionMap = new HashMap();
+
+ private int getOptionLength(String optionName)
+ {
+ registerOptions();
+ DocletOption option = (DocletOption)nameToOptionMap.get(optionName.toLowerCase());
+ if (null != option) {
+ return option.getLength();
+ }
+ else {
+ return -1;
+ }
+ }
+
+ protected List getKnownDirectSubclasses(ClassDoc classDoc)
+ {
+ List result = new LinkedList();
+ if (!"java.lang.Object".equals(classDoc.qualifiedName())) {
+ ClassDoc[] classes = rootDoc.classes();
+ for (int i=0; i<classes.length; ++i) {
+ if (classDoc == classes[i].superclass()) {
+ result.add(classes[i]);
+ }
+ }
+ }
+ return result;
+ }
+
+ protected static class IndexKey
+ implements Comparable
+ {
+ private String name;
+ private String lowerName;
+
+ public IndexKey(String name)
+ {
+ this.name = name;
+ this.lowerName = name.toLowerCase();
+ }
+
+ public boolean equals(Object other)
+ {
+ return this.lowerName.equals(((IndexKey)other).lowerName);
+ }
+
+ public int hashCode()
+ {
+ return lowerName.hashCode();
+ }
+
+ public int compareTo(Object other)
+ {
+ return lowerName.compareTo(((IndexKey)other).lowerName);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+ }
+
+ private Map categorizedIndex;
+
+ protected Map getCategorizedIndex()
+ {
+ if (null == categorizedIndex) {
+ categorizedIndex = new LinkedHashMap();
+
+ Map indexMap = getIndexByName();
+ LinkedList keys = new LinkedList(); //indexMap.keySet().size());
+ keys.addAll(indexMap.keySet());
+ Collections.sort(keys);
+ Iterator it = keys.iterator(); //indexMap.keySet().iterator();
+ char previousCategoryLetter = '\0';
+ Character keyLetter = null;
+ while (it.hasNext()) {
+ IndexKey key = (IndexKey)it.next();
+ char firstChar = Character.toUpperCase(key.getName().charAt(0));
+ if (firstChar != previousCategoryLetter) {
+ keyLetter = new Character(firstChar);
+ previousCategoryLetter = firstChar;
+ categorizedIndex.put(keyLetter, new LinkedList());
+ }
+ List letterList = (List)categorizedIndex.get(keyLetter);
+ letterList.add(indexMap.get(key));
+ }
+ }
+
+ return categorizedIndex;
+ }
+
+
+ private Map indexByName;
+
+ protected Map getIndexByName()
+ {
+ if (null == indexByName) {
+ // Create index
+
+ // Collect index
+
+ indexByName = new HashMap(); //TreeMap();
+
+ // Add packages to index
+
+ PackageDoc[] packages = rootDoc.specifiedPackages();
+ for (int i=0, ilim=packages.length; i<ilim; ++i) {
+ PackageDoc c = packages[i];
+ if (c.name().length() > 0) {
+ indexByName.put(new IndexKey(c.name()), c);
+ }
+ }
+
+ // Add classes, fields and methods to index
+
+ ClassDoc[] sumclasses = rootDoc.classes();
+ for (int i=0, ilim=sumclasses.length; i<ilim; ++i) {
+ ClassDoc c = sumclasses[i];
+ if (null == c.containingClass()) {
+ indexByName.put(new IndexKey(c.name() + " " + c.containingPackage().name()), c);
+ }
+ else {
+ indexByName.put(new IndexKey(c.name().substring(c.containingClass().name().length() + 1)
+ + " " + c.containingClass().name() + " " + c.containingPackage().name()), c);
+ }
+ FieldDoc[] fields = c.fields();
+ for (int j=0, jlim=fields.length; j<jlim; ++j) {
+ indexByName.put(new IndexKey(fields[j].name() + " " + fields[j].containingClass().name() + " " + fields[j].containingPackage().name()), fields[j]);
+ }
+ MethodDoc[] methods = c.methods();
+ for (int j=0, jlim=methods.length; j<jlim; ++j) {
+ MethodDoc method = methods[j];
+ indexByName.put(new IndexKey(method.name() + method.signature() + " " + method.containingClass().name() + " " + method.containingPackage().name()), method);
+ }
+ ConstructorDoc[] constructors = c.constructors();
+ for (int j=0, jlim=constructors.length; j<jlim; ++j) {
+ ConstructorDoc constructor = constructors[j];
+ indexByName.put(new IndexKey(constructor.name() + constructor.signature() + " " + constructor.containingClass().name() + " " + constructor.containingPackage().name()), constructor);
+ }
+ }
+ }
+ return indexByName;
+ }
+
+ private void registerTaglet(Taglet taglet)
+ {
+ tagletMap.put(taglet.getName(), taglet);
+ }
+
+ protected void printTaglets(Tag[] tags, TagletContext context, TagletPrinter output, boolean inline)
+ {
+ for (Iterator it = tagletMap.keySet().iterator(); it.hasNext(); ) {
+ String tagName = (String)it.next();
+ Object o = tagletMap.get(tagName);
+ Taglet taglet = (Taglet)o;
+ Doc doc = context.getDoc();
+ if (inline == taglet.isInlineTag()
+ && ((doc == null
+ && taglet.inOverview())
+ || (doc != null
+ && ((doc.isConstructor() && taglet.inConstructor())
+ || (doc.isField() && taglet.inField())
+ || (doc.isMethod() && taglet.inMethod())
+ || (doc instanceof PackageDoc && taglet.inPackage())
+ || ((doc.isClass() || doc.isInterface()) && taglet.inType()))))) {
+
+ List tagsOfThisType = new LinkedList();
+ for (int i=0; i<tags.length; ++i) {
+ if (tags[i].name().substring(1).equals(tagName)) {
+ tagsOfThisType.add(tags[i]);
+ }
+ }
+
+ Tag[] tagletTags = (Tag[])tagsOfThisType.toArray(new Tag[tagsOfThisType.size()]);
+
+ String tagletString;
+ if (taglet instanceof StandardTaglet) {
+ tagletString = renderTag(tagName, tagletTags, context);
+ }
+ else if (taglet instanceof GnuExtendedTaglet) {
+ tagletString = ((GnuExtendedTaglet)taglet).toString(tagletTags, context);
+ }
+ else {
+ tagletString = taglet.toString(tagletTags);
+ }
+ if (null != tagletString) {
+ output.printTagletString(tagletString);
+ }
+ }
+ }
+ }
+
+ protected void printInlineTaglet(Tag tag, TagletContext context, TagletPrinter output)
+ {
+ Taglet taglet = (Taglet)tagletMap.get(tag.name().substring(1));
+ if (null != taglet) {
+ String tagletString;
+ if (taglet instanceof GnuExtendedTaglet) {
+ tagletString = ((GnuExtendedTaglet)taglet).toString(tag, context);
+ }
+ else {
+ tagletString = taglet.toString(tag);
+ }
+ if (null != tagletString) {
+ output.printTagletString(tagletString);
+ }
+ }
+ else {
+ printWarning("Unknown tag: " + tag.name());
+ }
+ }
+
+ protected void printMainTaglets(Tag[] tags, TagletContext context, TagletPrinter output)
+ {
+ printTaglets(tags, context, output, false);
+ }
+
+ /**
+ * @param usedClassToPackagesMap ClassDoc to (PackageDoc to (UsageType to (Set of Doc)))
+ */
+ private void addUsedBy(Map usedClassToPackagesMap,
+ ClassDoc usedClass, UsageType usageType, Doc user, PackageDoc userPackage)
+ {
+ Map packageToUsageTypeMap = (Map)usedClassToPackagesMap.get(usedClass);
+ if (null == packageToUsageTypeMap) {
+ packageToUsageTypeMap = new HashMap();
+ usedClassToPackagesMap.put(usedClass, packageToUsageTypeMap);
+ }
+
+ Map usageTypeToUsersMap = (Map)packageToUsageTypeMap.get(userPackage);
+ if (null == usageTypeToUsersMap) {
+ usageTypeToUsersMap = new TreeMap();
+ packageToUsageTypeMap.put(userPackage, usageTypeToUsersMap);
+ }
+
+ Set userSet = (Set)usageTypeToUsersMap.get(usageType);
+ if (null == userSet) {
+ userSet = new TreeSet(); // FIXME: we need the collator from Main here
+ usageTypeToUsersMap.put(usageType, userSet);
+ }
+ userSet.add(user);
+ }
+
+ /**
+ * Create the cross reference database.
+ */
+ private Map collectUsage() {
+
+ Map _usedClassToPackagesMap = new HashMap();
+
+ ClassDoc[] classes = rootDoc.classes();
+ for (int i = 0, ilim = classes.length; i < ilim; ++ i) {
+ ClassDoc clazz = classes[i];
+
+ if (clazz.isInterface()) {
+ // classes implementing
+ InterfaceRelation relation
+ = (InterfaceRelation)getInterfaceRelations().get(clazz);
+ Iterator it = relation.implementingClasses.iterator();
+ while (it.hasNext()) {
+ ClassDoc implementor = (ClassDoc)it.next();
+ addUsedBy(_usedClassToPackagesMap,
+ clazz, UsageType.CLASS_IMPLEMENTING, implementor, implementor.containingPackage());
+ }
+ }
+ else {
+ // classes derived from
+ for (ClassDoc superclass = clazz.superclass(); superclass != null;
+ superclass = superclass.superclass()) {
+ addUsedBy(_usedClassToPackagesMap,
+ superclass, UsageType.CLASS_DERIVED_FROM, clazz, clazz.containingPackage());
+ }
+ }
+
+ FieldDoc[] fields = clazz.fields();
+ for (int j = 0, jlim = fields.length; j < jlim; ++ j) {
+ FieldDoc field = fields[j];
+
+ // fields of type
+ ClassDoc fieldType = field.type().asClassDoc();
+ if (null != fieldType) {
+ addUsedBy(_usedClassToPackagesMap,
+ fieldType, UsageType.FIELD_OF_TYPE,
+ field, clazz.containingPackage());
+ }
+ }
+
+ MethodDoc[] methods = clazz.methods();
+ for (int j = 0, jlim = methods.length; j < jlim; ++ j) {
+ MethodDoc method = methods[j];
+
+ // methods with return type
+
+ ClassDoc returnType = method.returnType().asClassDoc();
+ if (null != returnType) {
+ addUsedBy(_usedClassToPackagesMap,
+ returnType, UsageType.METHOD_WITH_RETURN_TYPE,
+ method, clazz.containingPackage());
+ }
+ Parameter[] parameters = method.parameters();
+ for (int k=0; k<parameters.length; ++k) {
+
+ // methods with parameter type
+
+ Parameter parameter = parameters[k];
+ ClassDoc parameterType = parameter.type().asClassDoc();
+ if (null != parameterType) {
+ addUsedBy(_usedClassToPackagesMap,
+ parameterType, UsageType.METHOD_WITH_PARAMETER_TYPE,
+ method, clazz.containingPackage());
+ }
+ }
+
+ // methods which throw
+
+ ClassDoc[] thrownExceptions = method.thrownExceptions();
+ for (int k = 0, klim = thrownExceptions.length; k < klim; ++ k) {
+ ClassDoc thrownException = thrownExceptions[k];
+ addUsedBy(_usedClassToPackagesMap,
+ thrownException, UsageType.METHOD_WITH_THROWN_TYPE,
+ method, clazz.containingPackage());
+ }
+ }
+
+ ConstructorDoc[] constructors = clazz.constructors();
+ for (int j = 0, jlim = constructors.length; j < jlim; ++ j) {
+
+ ConstructorDoc constructor = constructors[j];
+
+ Parameter[] parameters = constructor.parameters();
+ for (int k = 0, klim = parameters.length; k < klim; ++ k) {
+
+ // constructors with parameter type
+
+ Parameter parameter = parameters[k];
+ ClassDoc parameterType = parameter.type().asClassDoc();
+ if (null != parameterType) {
+ addUsedBy(_usedClassToPackagesMap,
+ parameterType, UsageType.CONSTRUCTOR_WITH_PARAMETER_TYPE,
+ constructor, clazz.containingPackage());
+ }
+ }
+
+ // constructors which throw
+
+ ClassDoc[] thrownExceptions = constructor.thrownExceptions();
+ for (int k = 0, klim = thrownExceptions.length; k < klim; ++ k) {
+ ClassDoc thrownException = thrownExceptions[k];
+ addUsedBy(_usedClassToPackagesMap,
+ thrownException, UsageType.CONSTRUCTOR_WITH_THROWN_TYPE,
+ constructor, clazz.containingPackage());
+ }
+ }
+ }
+ return _usedClassToPackagesMap;
+ }
+
+ private Map usedClassToPackagesMap = null;
+
+ protected Map getUsageOfClass(ClassDoc classDoc)
+ {
+ if (null == this.usedClassToPackagesMap) {
+ this.usedClassToPackagesMap = collectUsage();
+ }
+ return (Map)this.usedClassToPackagesMap.get(classDoc);
+ }
+
+ protected static class UsageType
+ implements Comparable
+ {
+ public static final UsageType CLASS_DERIVED_FROM = new UsageType("class-derived-from");
+ public static final UsageType CLASS_IMPLEMENTING = new UsageType("class-implementing");
+ public static final UsageType FIELD_OF_TYPE = new UsageType("field-of-type");
+ public static final UsageType METHOD_WITH_RETURN_TYPE = new UsageType("method-with-return-type");
+ public static final UsageType METHOD_WITH_PARAMETER_TYPE = new UsageType("method-with-parameter-type");
+ public static final UsageType METHOD_WITH_THROWN_TYPE = new UsageType("method-with-thrown-type");
+ public static final UsageType CONSTRUCTOR_WITH_PARAMETER_TYPE = new UsageType("constructor-with-parameter-type");
+ public static final UsageType CONSTRUCTOR_WITH_THROWN_TYPE = new UsageType("constructor-with-thrown-type");
+ private String id;
+
+ private UsageType(String id)
+ {
+ this.id = id;
+ }
+
+ public int compareTo(Object other)
+ {
+ return this.id.compareTo(((UsageType)other).id);
+ }
+
+ public String toString() {
+ return "UsageType{id=" + id + "}";
+ }
+
+ public String getId() {
+ return id;
+ }
+ }
+
+ private ResourceBundle resources;
+
+ protected String getString(String key)
+ {
+ if (null == resources) {
+ Locale currentLocale = Locale.getDefault();
+
+ resources
+ = ResourceBundle.getBundle("htmldoclet.HtmlDoclet", currentLocale);
+ }
+
+ return resources.getString(key);
+ }
+
+ protected String format(String key, String value1)
+ {
+ return MessageFormat.format(getString(key), new Object[] { value1 });
+ }
+
+ protected List getPackageGroups()
+ {
+ return packageGroups;
+ }
+
+ protected void copyDocFiles(File sourceDir, File targetDir)
+ throws IOException
+ {
+ File sourceDocFiles = new File(sourceDir, "doc-files");
+ File targetDocFiles = new File(targetDir, "doc-files");
+
+ if (sourceDocFiles.exists()) {
+ IOToolkit.copyDirectory(sourceDocFiles,
+ targetDocFiles,
+ optionDocFilesSubDirs.getValue(),
+ optionExcludeDocFilesSubDir.getComponents());
+ }
+ }
+
+ private Set sourcePaths;
+
+ /**
+ * Try to determine the source directory for the given package by
+ * looking at the path specified by -sourcepath, or the current
+ * directory if -sourcepath hasn't been specified.
+ *
+ * @throws IOException if the source directory couldn't be
+ * located.
+ *
+ * @return List of File
+ */
+ protected List getPackageSourceDirs(PackageDoc packageDoc)
+ throws IOException
+ {
+ if (null == sourcePaths) {
+ for (int i=0; i<rootDoc.options().length; ++i) {
+ if ("-sourcepath".equals(rootDoc.options()[i][0])
+ || "-s".equals(rootDoc.options()[i][0])) {
+ sourcePaths = new LinkedHashSet();
+ String sourcepathString = rootDoc.options()[i][1];
+ StringTokenizer st = new StringTokenizer(sourcepathString, File.pathSeparator);
+ while (st.hasMoreTokens()) {
+ sourcePaths.add(new File(st.nextToken()));
+ }
+ }
+ }
+ if (null == sourcePaths) {
+ sourcePaths = new LinkedHashSet();
+ sourcePaths.add(new File(System.getProperty("user.dir")));
+ }
+ }
+
+ String packageSubDir = packageDoc.name().replace('.', File.separatorChar);
+ Iterator it = sourcePaths.iterator();
+ List result = new LinkedList();
+ while (it.hasNext()) {
+ File pathComponent = (File)it.next();
+ File packageDir = new File(pathComponent, packageSubDir);
+ if (packageDir.exists()) {
+ result.add(packageDir);
+ }
+ }
+ if (result.isEmpty()) {
+ throw new IOException("Couldn't locate source directory for package " + packageDoc.name());
+ }
+ else {
+ return result;
+ }
+ }
+
+ protected File getSourceFile(ClassDoc classDoc)
+ throws IOException
+ {
+ List packageDirs = getPackageSourceDirs(classDoc.containingPackage());
+ Iterator it = packageDirs.iterator();
+ while (it.hasNext()) {
+ File packageDir = (File)it.next();
+ File sourceFile = new File(packageDir, getOuterClassDoc(classDoc).name() + ".java");
+ if (sourceFile.exists()) {
+ return sourceFile;
+ }
+ }
+
+ throw new IOException("Couldn't locate source file for class " + classDoc.qualifiedTypeName());
+ }
+
+ protected void printError(String error)
+ {
+ if (null != rootDoc) {
+ rootDoc.printError(error);
+ }
+ else {
+ System.err.println("ERROR: "+error);
+ }
+ }
+
+ protected void printWarning(String warning)
+ {
+ if (null != rootDoc) {
+ rootDoc.printWarning(warning);
+ }
+ else {
+ System.err.println("WARNING: "+warning);
+ }
+ }
+
+ protected void printNotice(String notice)
+ {
+ if (null != rootDoc) {
+ rootDoc.printNotice(notice);
+ }
+ else {
+ System.err.println(notice);
+ }
+ }
+
+ protected static ClassDoc getOuterClassDoc(ClassDoc classDoc)
+ {
+ while (null != classDoc.containingClass()) {
+ classDoc = classDoc.containingClass();
+ }
+ return classDoc;
+ }
+
+ private SortedSet allPackages;
+
+ protected Set getAllPackages()
+ {
+ if (null == this.allPackages) {
+ allPackages = new TreeSet();
+ PackageDoc[] specifiedPackages = rootDoc.specifiedPackages();
+ for (int i=0; i<specifiedPackages.length; ++i) {
+ allPackages.add(specifiedPackages[i]);
+ }
+ ClassDoc[] specifiedClasses = rootDoc.specifiedClasses();
+ for (int i=0; i<specifiedClasses.length; ++i) {
+ allPackages.add(specifiedClasses[i].containingPackage());
+ }
+ }
+ return this.allPackages;
+ }
+
+ protected boolean omitPackageQualifier(PackageDoc packageDoc)
+ {
+ if (!optionNoQualifier.isSpecified()) {
+ return false;
+ }
+ else {
+ return optionNoQualifier.match(packageDoc);
+ }
+ }
+
+ protected String possiblyQualifiedName(Type type)
+ {
+ if (null == type.asClassDoc()
+ || !omitPackageQualifier(type.asClassDoc().containingPackage())) {
+ return type.qualifiedTypeName();
+ }
+ else {
+ return type.typeName();
+ }
+ }
+
+ protected static class InterfaceRelation
+ {
+ public Set superInterfaces;
+ public Set subInterfaces;
+ public Set implementingClasses;
+
+ public InterfaceRelation()
+ {
+ superInterfaces = new TreeSet();
+ subInterfaces = new TreeSet();
+ implementingClasses = new TreeSet();
+ }
+ }
+
+ private void addAllInterfaces(ClassDoc classDoc, Set allInterfaces)
+ {
+ ClassDoc[] interfaces = classDoc.interfaces();
+ for (int i=0; i<interfaces.length; ++i) {
+ allInterfaces.add(interfaces[i]);
+ addAllInterfaces(interfaces[i], allInterfaces);
+ }
+ }
+
+ private Map allSubClasses;
+
+ protected Map getAllSubClasses()
+ {
+ if (null == allSubClasses) {
+ allSubClasses = new HashMap();
+
+ ClassDoc[] classDocs = getRootDoc().classes();
+ for (int i=0; i<classDocs.length; ++i) {
+ if (!classDocs[i].isInterface()) {
+ for (ClassDoc cd = classDocs[i].superclass();
+ null != cd;
+ cd = cd.superclass()) {
+
+ if (!cd.qualifiedTypeName().equals("java.lang.Object")) {
+ List subClasses = (List)allSubClasses.get(cd);
+ if (null == subClasses) {
+ subClasses = new LinkedList();
+ allSubClasses.put(cd, subClasses);
+ }
+ subClasses.add(classDocs[i]);
+ }
+ }
+ }
+ }
+ }
+ return allSubClasses;
+ }
+
+ private Map interfaceRelations;
+
+ private void addToInterfaces(ClassDoc classDoc, ClassDoc[] interfaces)
+ {
+ for (int i=0; i<interfaces.length; ++i) {
+ InterfaceRelation interfaceRelation
+ = (InterfaceRelation)interfaceRelations.get(interfaces[i]);
+ if (null == interfaceRelation) {
+ interfaceRelation = new InterfaceRelation();
+ interfaceRelations.put(interfaces[i], interfaceRelation);
+ }
+ interfaceRelation.implementingClasses.add(classDoc);
+ addToInterfaces(classDoc, interfaces[i].interfaces());
+ }
+ }
+
+ protected Map getInterfaceRelations()
+ {
+ if (null == interfaceRelations) {
+ interfaceRelations = new HashMap();
+
+ ClassDoc[] classDocs = getRootDoc().classes();
+ for (int i=0; i<classDocs.length; ++i) {
+ if (classDocs[i].isInterface()) {
+ InterfaceRelation relation = new InterfaceRelation();
+ addAllInterfaces(classDocs[i], relation.superInterfaces);
+ interfaceRelations.put(classDocs[i], relation);
+ }
+ }
+
+ Iterator it = interfaceRelations.keySet().iterator();
+ while (it.hasNext()) {
+ ClassDoc interfaceDoc = (ClassDoc)it.next();
+ InterfaceRelation relation
+ = (InterfaceRelation)interfaceRelations.get(interfaceDoc);
+ Iterator superIt = relation.superInterfaces.iterator();
+ while (superIt.hasNext()) {
+ ClassDoc superInterfaceDoc = (ClassDoc)superIt.next();
+ InterfaceRelation superRelation
+ = (InterfaceRelation)interfaceRelations.get(superInterfaceDoc);
+ if (null != superRelation) {
+ superRelation.subInterfaces.add(interfaceDoc);
+ }
+ }
+ }
+
+ for (int i=0; i<classDocs.length; ++i) {
+ if (!classDocs[i].isInterface()) {
+ for (ClassDoc cd = classDocs[i]; null != cd; cd = cd.superclass()) {
+ addToInterfaces(classDocs[i], cd.interfaces());
+ }
+ }
+ }
+ }
+
+ return interfaceRelations;
+ }
+
+ private Map sortedMethodMap = new HashMap();
+
+ protected MethodDoc[] getSortedMethods(ClassDoc classDoc)
+ {
+ MethodDoc[] result = (MethodDoc[])sortedMethodMap.get(classDoc);
+ if (null == result) {
+ MethodDoc[] methods = classDoc.methods();
+ result = (MethodDoc[])methods.clone();
+ Arrays.sort(result);
+ return result;
+ }
+ return result;
+ }
+
+ private Map sortedConstructorMap = new HashMap();
+
+ protected ConstructorDoc[] getSortedConstructors(ClassDoc classDoc)
+ {
+ ConstructorDoc[] result = (ConstructorDoc[])sortedConstructorMap.get(classDoc);
+ if (null == result) {
+ ConstructorDoc[] constructors = classDoc.constructors();
+ result = (ConstructorDoc[])constructors.clone();
+ Arrays.sort(result);
+ return result;
+ }
+ return result;
+ }
+
+ private Map sortedFieldMap = new HashMap();
+
+ protected FieldDoc[] getSortedFields(ClassDoc classDoc)
+ {
+ FieldDoc[] result = (FieldDoc[])sortedFieldMap.get(classDoc);
+ if (null == result) {
+ FieldDoc[] fields = classDoc.fields();
+ result = (FieldDoc[])fields.clone();
+ Arrays.sort(result);
+ return result;
+ }
+ return result;
+ }
+
+ private Map sortedInnerClassMap = new HashMap();
+
+ protected ClassDoc[] getSortedInnerClasses(ClassDoc classDoc)
+ {
+ ClassDoc[] result = (ClassDoc[])sortedInnerClassMap.get(classDoc);
+ if (null == result) {
+ ClassDoc[] innerClasses = classDoc.innerClasses();
+ result = (ClassDoc[])innerClasses.clone();
+ Arrays.sort(result);
+ return result;
+ }
+ return result;
+ }
+
+ protected abstract String renderTag(String tagName, Tag[] tags, TagletContext context);
+
+ protected abstract String getDocletVersion();
+
+ protected SortedSet getThrownExceptions(ExecutableMemberDoc execMemberDoc)
+ {
+ SortedSet result = new TreeSet();
+ ClassDoc[] thrownExceptions = execMemberDoc.thrownExceptions();
+ for (int j=0; j<thrownExceptions.length; ++j) {
+ result.add(thrownExceptions[j]);
+ }
+ return result;
+ }
+
+ protected boolean isUncheckedException(ClassDoc classDoc)
+ {
+ if (classDoc.isException()) {
+ while (null != classDoc) {
+ if (classDoc.qualifiedTypeName().equals("java.lang.RuntimeException")) {
+ return true;
+ }
+ classDoc = classDoc.superclass();
+ }
+ return false;
+ }
+ else {
+ return false;
+ }
+ }
+
+ protected FieldDoc findField(ClassDoc classDoc, String fieldName)
+ {
+ for (ClassDoc cd = classDoc; cd != null; cd = cd.superclass()) {
+ FieldDoc[] fields = cd.fields(false);
+ for (int i=0; i<fields.length; ++i) {
+ if (fields[i].name().equals(fieldName)) {
+ return fields[i];
+ }
+ }
+ }
+ return null;
+ }
+
+ private Map implementedInterfacesCache = new HashMap();
+
+ protected Set getImplementedInterfaces(ClassDoc classDoc)
+ {
+ Set result = (Set)implementedInterfacesCache.get(classDoc);
+ if (null == result) {
+ result = new TreeSet();
+
+ for (ClassDoc cd = classDoc; cd != null; cd = cd.superclass()) {
+ ClassDoc[] interfaces = cd.interfaces();
+ for (int i=0; i<interfaces.length; ++i) {
+ result.add(interfaces[i]);
+ InterfaceRelation relation
+ = (InterfaceRelation)getInterfaceRelations().get(interfaces[i]);
+ if (null != relation) {
+ result.addAll(relation.superInterfaces);
+ }
+ }
+ }
+
+ implementedInterfacesCache.put(classDoc, result);
+ }
+
+ return result;
+ }
+
+ protected boolean isSinglePackage()
+ {
+ return getAllPackages().size() <= 1;
+ }
+
+ protected PackageDoc getSinglePackage()
+ {
+ return (PackageDoc)getAllPackages().iterator().next();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletConfigurationException.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletConfigurationException.java
new file mode 100644
index 000000000..0e29df928
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletConfigurationException.java
@@ -0,0 +1,54 @@
+/* gnu.classpath.tools.doclets.DocletConfigurationException
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+/**
+ * Thrown by <code>AbstractDoclet</code> members or members of
+ * <code>AbstractDoclet</code> subclasses when a problem caused by
+ * user-specified options is detected.
+ *
+ * @see AbstractDoclet
+ */
+public class DocletConfigurationException
+ extends Exception
+{
+ public DocletConfigurationException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOption.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOption.java
new file mode 100644
index 000000000..fa67f5ec7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOption.java
@@ -0,0 +1,56 @@
+/* gnu.classpath.tools.doclets.DocletOption
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+public abstract class DocletOption
+{
+ private String optionName;
+
+ protected DocletOption(String optionName)
+ {
+ this.optionName = optionName;
+ }
+
+ public String getName()
+ {
+ return this.optionName;
+ }
+
+ public abstract int getLength();
+ public abstract boolean set(String[] optionArr);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionColonSeparated.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionColonSeparated.java
new file mode 100644
index 000000000..e02e1ebb4
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionColonSeparated.java
@@ -0,0 +1,76 @@
+/* gnu.classpath.tools.doclets.DocletOptionColonSeparated
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Processes a doclet option whose value consists of a
+ * colon-separated list of strings.
+ */
+public class DocletOptionColonSeparated
+ extends DocletOption
+{
+ private Set components = new LinkedHashSet();
+
+ DocletOptionColonSeparated(String optionName)
+ {
+ super(optionName);
+ }
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ StringTokenizer st = new StringTokenizer(":");
+ while (st.hasMoreTokens()) {
+ components.add(st.nextToken());
+ }
+ return true;
+ }
+
+ public Set getComponents()
+ {
+ return components;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFile.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFile.java
new file mode 100644
index 000000000..b83685755
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFile.java
@@ -0,0 +1,77 @@
+/* gnu.classpath.tools.doclets.DocletOptionFile
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import java.io.File;
+
+/**
+ * Processes a doclet option whose value denotes an existing or
+ * non-existing file in the local file system.
+ */
+public class DocletOptionFile
+ extends DocletOption
+{
+ private File value;
+
+ public DocletOptionFile(String optionName)
+ {
+ this(optionName, null);
+ }
+
+ public DocletOptionFile(String optionName, File defaultFile)
+ {
+ super(optionName);
+ this.value = defaultFile;
+ }
+
+ public File getValue()
+ {
+ return this.value;
+ }
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ this.value = new File(optionArr[1]);
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFlag.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFlag.java
new file mode 100644
index 000000000..13afe407f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionFlag.java
@@ -0,0 +1,69 @@
+/* gnu.classpath.tools.doclets.DocletOptionFlag
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+/**
+ * Processes a doclet option without a value whose existance denotes
+ * that a specific feature should be enabled or disabled.
+ */
+public class DocletOptionFlag
+ extends DocletOption
+{
+ private boolean value = false;
+
+ public DocletOptionFlag(String optionName)
+ {
+ super(optionName);
+ }
+
+ public boolean getValue()
+ {
+ return this.value;
+ }
+
+ public int getLength()
+ {
+ return 1;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ value = true;
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionPackageWildcard.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionPackageWildcard.java
new file mode 100644
index 000000000..33a637db8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionPackageWildcard.java
@@ -0,0 +1,124 @@
+/* gnu.classpath.tools.doclets.DocletOptionPackageWildcard
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import com.sun.javadoc.PackageDoc;
+
+/**
+ * Processes a doclet option whose value consists of a
+ * colon-separated list of package wildcards, or - optionally -
+ * equals the string "all", denoting that all packages should match.
+ */
+public class DocletOptionPackageWildcard
+ extends DocletOption
+{
+ private PackageMatcher packageMatcher;
+ private boolean allowAll;
+ private boolean specified;
+
+ DocletOptionPackageWildcard(String optionName, boolean allowAll)
+ {
+ super(optionName);
+ this.allowAll = allowAll;
+ }
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean isSpecified()
+ {
+ return specified;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ this.specified = true;
+ try {
+ if (allowAll && "all".equals(optionArr[2])) {
+ packageMatcher = null;
+ }
+ else {
+ packageMatcher = new PackageMatcher();
+
+ StringTokenizer tokenizer = new StringTokenizer(optionArr[2], ":");
+ while (tokenizer.hasMoreTokens()) {
+ String packageWildcard = tokenizer.nextToken();
+ packageMatcher.addWildcard(packageWildcard);
+ }
+ }
+ return true;
+ }
+ catch (InvalidPackageWildcardException e) {
+ // FIXME: output problem description here, better throw
+ // DocletConfigurationException
+ return false;
+ }
+ }
+
+ public SortedSet filter(PackageDoc[] packages)
+ {
+ if (null != packageMatcher) {
+ return packageMatcher.filter(packages);
+ }
+ else {
+ SortedSet result = new TreeSet();
+ for (int i=0; i<packages.length; ++i) {
+ result.add(packages[i]);
+ }
+ return result;
+ }
+ }
+
+ public boolean match(PackageDoc packageDoc)
+ {
+ if (null != packageMatcher) {
+ return packageMatcher.match(packageDoc);
+ }
+ else {
+ return true;
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionString.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionString.java
new file mode 100644
index 000000000..ecab86541
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/DocletOptionString.java
@@ -0,0 +1,68 @@
+/* gnu.classpath.tools.doclets.DocletOptionString
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+/**
+ * Processes a doclet option whose value is an arbitrary string.
+ */
+public class DocletOptionString
+ extends DocletOption
+{
+ private String value = null;
+
+ public DocletOptionString(String optionName)
+ {
+ super(optionName);
+ }
+
+ public String getValue()
+ {
+ return this.value;
+ }
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ value = optionArr[1];
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/InlineTagRenderer.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/InlineTagRenderer.java
new file mode 100644
index 000000000..f7d4ac573
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/InlineTagRenderer.java
@@ -0,0 +1,46 @@
+/* gnu.classpath.tools.doclets.InlineTagRenderer
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import com.sun.javadoc.Tag;
+import gnu.classpath.tools.taglets.TagletContext;
+
+public interface InlineTagRenderer
+{
+ public String renderInlineTags(Tag[] tags, TagletContext context);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/InvalidPackageWildcardException.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/InvalidPackageWildcardException.java
new file mode 100644
index 000000000..8f34288a3
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/InvalidPackageWildcardException.java
@@ -0,0 +1,51 @@
+/* gnu.classpath.tools.doclets.InvalidPackageWildcardException
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+/**
+ * Thrown when an invalid wildcard pattern is passed to {@link
+ * PackageMatcher.addWildcard(String)}.
+ */
+public class InvalidPackageWildcardException
+ extends Exception
+{
+ public InvalidPackageWildcardException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/PackageGroup.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/PackageGroup.java
new file mode 100644
index 000000000..4278ffb98
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/PackageGroup.java
@@ -0,0 +1,58 @@
+/* gnu.classpath.tools.doclets.PackageGroup
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import java.util.SortedSet;
+
+/**
+ * Stores a package group given on the command line.
+ */
+public class PackageGroup
+{
+ private String name;
+ private SortedSet packages; // contains PackageDoc
+
+ public PackageGroup(String name, SortedSet packages)
+ {
+ this.name = name;
+ this.packages = packages;
+ }
+
+ public String getName() { return name; }
+ public SortedSet getPackages() { return packages; }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/PackageMatcher.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/PackageMatcher.java
new file mode 100644
index 000000000..196b74c88
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/PackageMatcher.java
@@ -0,0 +1,152 @@
+/* gnu.classpath.tools.doclets.PackageMatcher
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.sun.javadoc.PackageDoc;
+
+/**
+ * Filters a set of packages according to a set of wildcards.
+ */
+public class PackageMatcher
+{
+ private Set patterns = new HashSet();
+
+ /**
+ * Add a wildcard to be matched. Wildcards can contain asterisk
+ * characters which match zero or more characters.
+ *
+ * @throw InvalidPackageWildcardException if the wildcard cannot
+ * match any valid package name.
+ */
+ public void addWildcard(String wildcard)
+ throws InvalidPackageWildcardException
+ {
+ final int STATE_ID_START = 0;
+ final int STATE_ID = 1;
+
+ int state = STATE_ID_START;
+
+ char[] wildcardChars = wildcard.toCharArray();
+ StringBuffer regexString = new StringBuffer();
+
+ for (int i=0; i<wildcardChars.length; ++i) {
+ char c = wildcardChars[i];
+ switch (state) {
+ case STATE_ID_START:
+ if ('*' == c) {
+ regexString.append(".*");
+ }
+ else if (Character.isJavaIdentifierStart(c)) {
+ regexString.append(c);
+ }
+ else {
+ throw new InvalidPackageWildcardException(wildcard);
+ }
+ state = STATE_ID;
+ break;
+
+ case STATE_ID:
+ if ('.' == c) {
+ regexString.append("\\.");
+ state = STATE_ID_START;
+ }
+ else if ('*' == c) {
+ regexString.append(".*");
+ }
+ else if (Character.isJavaIdentifierPart(c)) {
+ regexString.append(c);
+ }
+ else {
+ throw new InvalidPackageWildcardException(wildcard);
+ }
+ }
+ }
+ if (STATE_ID_START == state) {
+ throw new InvalidPackageWildcardException(wildcard);
+ }
+
+ patterns.add(Pattern.compile(regexString.toString()));
+ }
+
+ /**
+ * Return a sorted, filtered set of packages. A package from the
+ * array given will be put into the output list if it matches one
+ * or more of the wildcards added to this PackageMatcher before.
+ */
+ public SortedSet filter(PackageDoc[] packageDocs)
+ {
+ SortedSet result = new TreeSet();
+ for (int i=0; i<packageDocs.length; ++i) {
+ if (match(packageDocs[i])) {
+ result.add(packageDocs[i]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return true when the given PackageDoc matches one or more of
+ * the wildcard added to this PackageMatcher before.
+ */
+ public boolean match(PackageDoc packageDoc)
+ {
+ Iterator it = patterns.iterator();
+ while (it.hasNext()) {
+ Pattern pattern = (Pattern)it.next();
+ Matcher matcher = pattern.matcher(packageDoc.name());
+ if (matcher.matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ return "PackageMatcher{patterns=" + patterns + "}";
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/StandardTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/StandardTaglet.java
new file mode 100644
index 000000000..f43f2a13c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/StandardTaglet.java
@@ -0,0 +1,100 @@
+/* gnu.classpath.tools.doclets.StandardTaglet
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+import com.sun.javadoc.Tag;
+import com.sun.tools.doclets.Taglet;
+
+/**
+ * Represents one of the built-in taglets. Used for specifying taglet
+ * order.
+ */
+public class StandardTaglet
+ implements Taglet
+{
+ private String name;
+
+ /**
+ * Initialize with one of the built-in taglet names.
+ */
+ public StandardTaglet(String name) {
+ this.name = name;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String toString(Tag tag) {
+ //assert(false);
+ return null;
+ }
+
+ public String toString(Tag[] tags) {
+ //assert(false);
+ return null;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/TagletPrinter.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/TagletPrinter.java
new file mode 100644
index 000000000..b59704a51
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/TagletPrinter.java
@@ -0,0 +1,46 @@
+/* gnu.classpath.tools.doclets.TagletPrinter
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets;
+
+/**
+ * Call-back interface for taglet string output.
+ */
+public interface TagletPrinter
+{
+ public void printTagletString(String s);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/debugdoclet/DebugDoclet.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/debugdoclet/DebugDoclet.java
new file mode 100644
index 000000000..18bf57950
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/debugdoclet/DebugDoclet.java
@@ -0,0 +1,174 @@
+/* DebugDoclet.java - Doclet for debugging
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.debugdoclet;
+
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.MethodDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.RootDoc;
+import com.sun.javadoc.Tag;
+
+import java.io.PrintStream;
+
+import java.util.Arrays;
+
+public class DebugDoclet
+{
+ public static boolean start(RootDoc rootDoc)
+ {
+ new DebugDoclet().run(rootDoc);
+ return true;
+ }
+
+ private PrintStream out;
+
+ public DebugDoclet()
+ {
+ out = System.out;
+ }
+
+ private void printHeader(String header)
+ {
+ out.println();
+ out.println("******** " + header + " ********");
+ out.println();
+ }
+
+ private void printSubHeader(String header)
+ {
+ out.println();
+ out.println("======== " + header + " ========");
+ out.println();
+ }
+
+ private void printSub2Header(String header)
+ {
+ out.println();
+ out.println("-------- " + header + " --------");
+ out.println();
+ }
+
+ private void run(RootDoc rootDoc)
+ {
+ printHeader("Overview");
+
+ printSubHeader("Specified Packages");
+
+ PackageDoc[] specifiedPackages = rootDoc.specifiedPackages();
+ Arrays.sort(specifiedPackages);
+ for (int i=0; i<specifiedPackages.length; ++i) {
+ out.println(specifiedPackages[i].name());
+ }
+
+ printSubHeader("Specified Classes");
+
+ ClassDoc[] specifiedClasses = rootDoc.specifiedClasses();
+ Arrays.sort(specifiedClasses);
+ for (int i=0; i<specifiedClasses.length; ++i) {
+ out.println(specifiedClasses[i].qualifiedTypeName());
+ }
+ printSubHeader("Classes");
+
+ ClassDoc[] classes = rootDoc.classes();
+ Arrays.sort(classes);
+ for (int i=0; i<classes.length; ++i) {
+ out.println(classes[i].qualifiedTypeName());
+ }
+
+ printHeader("Class Detail");
+
+ for (int i=0; i<classes.length; ++i) {
+ printSubHeader(classes[i].qualifiedTypeName());
+
+ printTags(classes[i].firstSentenceTags());
+
+ printSub2Header("Methods");
+
+ MethodDoc[] methods = classes[i].methods();
+
+ for (int j=0; j<methods.length; ++j) {
+ out.println("name: \"" + methods[j].name() + "\"");
+ out.println("signature: \"" + methods[j].signature() + "\"");
+ out.println("modifiers: \"" + methods[j].modifiers() + "\"");
+ out.print("throws: ");
+ ClassDoc[] thrownExceptions = methods[j].thrownExceptions();
+ for (int k=0; k<thrownExceptions.length; ++k) {
+ if (k>0) { out.print(", "); }
+ out.print(thrownExceptions[k].qualifiedTypeName());
+ }
+ out.println();
+ }
+
+ printSub2Header("Fields");
+
+ FieldDoc[] fields = classes[i].fields();
+
+ for (int j=0; j<fields.length; ++j) {
+ out.println("name: \"" + fields[j].name() + "\"");
+ out.println("modifiers: \"" + fields[j].modifiers() + "\"");
+ out.println();
+ }
+
+ printSub2Header("Serializable Fields");
+
+ FieldDoc[] sfields = classes[i].serializableFields();
+
+ for (int j=0; j<sfields.length; ++j) {
+ out.println("name: \"" + sfields[j].name() + "\"");
+ out.println("modifiers: \"" + sfields[j].modifiers() + "\"");
+ out.println();
+ }
+ }
+ }
+
+ private void printTag(Tag tag)
+ {
+ if (null != tag.text()) {
+ System.out.println(tag.text());
+ }
+ }
+
+ private void printTags(Tag[] tags)
+ {
+ for (int i=0; i<tags.length; ++i) {
+ out.println("Tag #" + (i+1) + ":");
+ printTag(tags[i]);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/CssClass.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/CssClass.java
new file mode 100644
index 000000000..ba4c8b685
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/CssClass.java
@@ -0,0 +1,300 @@
+/* gnu.classpath.tools.doclets.htmldoclet.CssClass
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.htmldoclet;
+
+/**
+ * Represents a CSS (Cascading Stylesheet) class. Supports
+ * substituting <code>div</code> and <code>span</code> tags by more
+ * specialized HTML tags.
+ */
+public class CssClass
+{
+ public static final CssClass BODY_MENU_PACKAGES = new CssClass("menu packages");
+ public static final CssClass BODY_MENU_CLASSES = new CssClass("menu classes");
+ public static final CssClass BODY_CONTENT_CLASS = new CssClass("content class");
+ public static final CssClass BODY_CONTENT_DEPRECATED = new CssClass("content deprecated");
+ public static final CssClass BODY_CONTENT_PACKAGE = new CssClass("content package");
+ public static final CssClass BODY_CONTENT_OVERVIEW = new CssClass("content overview");
+ public static final CssClass BODY_CONTENT_ABOUT = new CssClass("content about");
+ public static final CssClass BODY_CONTENT_HELP = new CssClass("content help");
+ public static final CssClass BODY_CONTENT_PACKAGE_TREE = new CssClass("content packagetree");
+ public static final CssClass BODY_CONTENT_FULL_TREE = new CssClass("content fulltree");
+ public static final CssClass BODY_CONTENT_INDEX = new CssClass("content index");
+ public static final CssClass BODY_CONTENT_USES = new CssClass("content uses");
+ public static final CssClass BODY_CONTENT_SOURCE = new CssClass("content source");
+
+ public static final CssClass OVERVIEW_TITLE = new CssClass("overview title", "h1");
+ public static final CssClass OVERVIEW_SUMMARY = new CssClass("overview summary");
+ public static final CssClass OVERVIEW_SUMMARY_LEFT = new CssClass("left");
+ public static final CssClass OVERVIEW_SUMMARY_RIGHT = new CssClass("right");
+ public static final CssClass OVERVIEW_DESCRIPTION_TOP = new CssClass("overview description top");
+ public static final CssClass OVERVIEW_DESCRIPTION_FULL = new CssClass("overview description full");
+
+ public static final CssClass DEPRECATION_TITLE = new CssClass("deprecation title", "h1");
+ public static final CssClass DEPRECATION_SUMMARY = new CssClass("summary");
+ public static final CssClass DEPRECATION_SUMMARY_LEFT = new CssClass("left");
+ public static final CssClass DEPRECATION_SUMMARY_DESCRIPTION = new CssClass("description");
+ public static final CssClass DEPRECATION_TOC = new CssClass("dep-toc");
+ public static final CssClass DEPRECATION_TOC_HEADER = new CssClass("header", "h3");
+ public static final CssClass DEPRECATION_TOC_LIST = new CssClass("list", "ul");
+ public static final CssClass DEPRECATION_TOC_ENTRY = new CssClass("entry", "li");
+ public static final CssClass DEPRECATION_EMPTY = new CssClass("dep-empty", "p");
+ public static final CssClass DEPRECATION_LIST = new CssClass("dep-list", "div");
+
+ public static final CssClass SERIALIZED_TITLE = new CssClass("serialized title", "h1");
+ public static final CssClass SERIALIZED_PACKAGE_HEADER = new CssClass("serialized package header", "h2");
+ public static final CssClass SERIALIZED_CLASS_HEADER = new CssClass("serialized class header", "h3");
+ public static final CssClass SERIALIZED_SVUID_OUTER = new CssClass("serialized svuid outer", "p");
+ public static final CssClass SERIALIZED_SVUID_HEADER = new CssClass("serialized svuid header", "b");
+ public static final CssClass SERIALIZED_SVUID_VALUE = new CssClass("serialized svuid header");
+ public static final CssClass SERIALIZED_SECTION = new CssClass("serialized section");
+ public static final CssClass SERIALIZED_SECTION_HEADER = new CssClass("serialized section header", "h4");
+
+ public static final CssClass PACKAGE_TITLE = new CssClass("package title", "h1");
+ public static final CssClass PACKAGE_SUMMARY = new CssClass("package summary");
+ public static final CssClass PACKAGE_SUMMARY_LEFT = new CssClass("left");
+ public static final CssClass PACKAGE_SUMMARY_RIGHT = new CssClass("right");
+ public static final CssClass PACKAGE_DESCRIPTION_TOP = new CssClass("package description top");
+ public static final CssClass PACKAGE_DESCRIPTION_FULL = new CssClass("package description full");
+ public static final CssClass PACKAGE_TREE_TITLE = new CssClass("package tree title", "h1");
+ public static final CssClass PACKAGE_TREE_SECTION_TITLE = new CssClass("package tree section title", "h2");
+ public static final CssClass PACKAGE_TREE = new CssClass("tree", "ul");
+
+ public static final CssClass TREE_LINK = new CssClass("tree link", "b");
+
+ public static final CssClass FULL_TREE_PACKAGELIST = new CssClass("fulltree package list", "dl");
+ public static final CssClass FULL_TREE_PACKAGELIST_HEADER = new CssClass("fulltree package header", "dt", "b");
+ public static final CssClass FULL_TREE_PACKAGELIST_ITEM = new CssClass("fulltree package item", "dd");
+
+ public static final CssClass PACKAGE_MENU_LIST = new CssClass("package menu-list", "div");
+ public static final CssClass PACKAGE_MENU_ENTRY = new CssClass("package menu-entry");
+ public static final CssClass PACKAGE_MENU_TITLE = new CssClass("package menu-title", "h4");
+
+ public static final CssClass CLASS_MENU_LIST = new CssClass("classes menu-list", "div");
+ public static final CssClass CLASS_MENU_TITLE = new CssClass("classes menu-title", "h4");
+ public static final CssClass CLASS_MENU_SUBTITLE = new CssClass("classes menu-subtitle", "p");
+ public static final CssClass CLASS_MENU_ENTRY_CLASS = new CssClass("classes menu-entry class");
+ public static final CssClass CLASS_MENU_ENTRY_INTERFACE = new CssClass("classes menu-entry interface", "i");
+
+ public static final CssClass INDEX_TITLE = new CssClass("index title", "h1");
+ public static final CssClass INDEX_CATEGORY = new CssClass("index category");
+ public static final CssClass INDEX_CATEGORY_HEADER = new CssClass("index category header", "h2");
+ public static final CssClass INDEX_ENTRY = new CssClass("index entry");
+ public static final CssClass INDEX_ENTRY_DESCRIPTION = new CssClass("description");
+ public static final CssClass INDEX_ENTRY_KEY = new CssClass("key");
+ public static final CssClass INDEX_LETTERS = new CssClass("index letters");
+ public static final CssClass INDEX_LETTER = new CssClass("index letter");
+ public static final CssClass INDEX_LETTER_SPACER = new CssClass("index letter spacer");
+
+ public static final CssClass CLASS_TITLE = new CssClass("class title outer");
+ public static final CssClass CLASS_TITLE_PACKAGE = new CssClass("class title-package", "h3");
+ public static final CssClass CLASS_TITLE_CLASS = new CssClass("class title-class", "h1");
+ public static final CssClass CLASS_SUBCLASSES = new CssClass("class subclasses", "dl");
+ public static final CssClass CLASS_SUBCLASSES_HEADER = new CssClass("class subclasses header", "dt", "b");
+ public static final CssClass CLASS_SUBCLASSES_ITEM = new CssClass("class subclasses header", "dd");
+ public static final CssClass CLASS_ENCLOSINGCLASS = new CssClass("class enclosing", "dl");
+ public static final CssClass CLASS_ENCLOSINGCLASS_HEADER = new CssClass("class enclosing header", "dt", "b");
+ public static final CssClass CLASS_ENCLOSINGCLASS_ITEM = new CssClass("class enclosing item", "dd");
+ public static final CssClass CLASS_KNOWNIMPLEMENTING = new CssClass("class knownimplementing", "dl");
+ public static final CssClass CLASS_KNOWNIMPLEMENTING_HEADER = new CssClass("header", "dt", "b");
+ public static final CssClass CLASS_KNOWNIMPLEMENTING_ITEM = new CssClass("item", "dd");
+ public static final CssClass CLASS_INHERITANCETREE = new CssClass("class inheritance-tree");
+ public static final CssClass CLASS_SYNOPSIS = new CssClass("class synopsis outer");
+ public static final CssClass CLASS_SYNOPSIS_NAME = new CssClass("class synopsis name", "b");
+ public static final CssClass CLASS_SYNOPSIS_DECLARATION = new CssClass("class synopsis declaration", "div", "code");
+ public static final CssClass CLASS_SYNOPSIS_SUPERCLASS = new CssClass("class synopsis superclass", "div", "code");
+ public static final CssClass CLASS_SYNOPSIS_IMPLEMENTS = new CssClass("class synopsis implements", "div", "code");
+ public static final CssClass CLASS_DESCRIPTION = new CssClass("class description");
+ public static final CssClass CLASS_SUMMARY = new CssClass("class summary");
+ public static final CssClass CLASS_SUMMARY_LEFT = new CssClass("left", new String[] { "valign" }, new String[] { "top" });
+ public static final CssClass CLASS_SUMMARY_LEFT_SYNOPSIS = new CssClass("synopsis", "code");
+ public static final CssClass CLASS_SUMMARY_RIGHT = new CssClass("right");
+ public static final CssClass CLASS_SUMMARY_RIGHT_LIST = new CssClass("list", "dl");
+ public static final CssClass CLASS_SUMMARY_RIGHT_SYNOPSIS = new CssClass("synopsis", "dt", "code");
+ public static final CssClass CLASS_SUMMARY_RIGHT_DESCRIPTION = new CssClass("description", "dd");
+ public static final CssClass CLASS_SUMMARY_INHERITED = new CssClass("inherited");
+ public static final CssClass CLASS_SUMMARY_INHERITED_MEMBER = new CssClass("member", "code");
+ public static final CssClass CLASS_BOILERPLATE = new CssClass("boilerplate", "pre", new String[] { "style" }, new String[] { "font-size: x-small;" });
+
+ public static final CssClass USAGE_TITLE = new CssClass("usage title", "h1");
+ public static final CssClass USAGE_PACKAGE_TITLE = new CssClass("usage package title", "h2");
+ public static final CssClass USAGE_USAGE_TITLE = new CssClass("usage usage title", "h3");
+ public static final CssClass USAGE_SUMMARY = new CssClass("usage summary");
+ public static final CssClass USAGE_SUMMARY_LEFT = new CssClass("left");
+ public static final CssClass USAGE_SUMMARY_RIGHT = new CssClass("right");
+ public static final CssClass USAGE_SUMMARY_SYNOPSIS = new CssClass("synopsis");
+ public static final CssClass USAGE_SUMMARY_DESCRIPTION = new CssClass("description");
+ public static final CssClass USAGE_TABLE_HEADER = new CssClass("table header", "h3");
+ public static final CssClass USAGE_EMPTY = new CssClass("usage empty", "p");
+
+ public static final CssClass MEMBER_DETAIL = new CssClass("member detail outer");
+ public static final CssClass MEMBER_DETAIL_NAME = new CssClass("member detail name", "h3");
+ public static final CssClass MEMBER_DETAIL_BODY = new CssClass("member detail name", "blockquote");
+ public static final CssClass MEMBER_DETAIL_SYNOPSIS = new CssClass("member detail synopsis", "pre");
+ public static final CssClass MEMBER_DETAIL_DESCRIPTION = new CssClass("member detail description");
+ public static final CssClass MEMBER_DETAIL_SPECIFIED_BY_LIST = new CssClass("member detail specified by list", "dl");
+ public static final CssClass MEMBER_DETAIL_SPECIFIED_BY_HEADER = new CssClass("member detail specified by header", "dt", "b");
+ public static final CssClass MEMBER_DETAIL_SPECIFIED_BY_ITEM = new CssClass("member detail specified by item", "dd");
+ public static final CssClass MEMBER_DETAIL_OVERRIDDEN_LIST = new CssClass("member detail overridden list", "dl");
+ public static final CssClass MEMBER_DETAIL_OVERRIDDEN_HEADER = new CssClass("member detail overridden header", "dt", "b");
+ public static final CssClass MEMBER_DETAIL_OVERRIDDEN_ITEM = new CssClass("member detail overridden item", "dd");
+ public static final CssClass MEMBER_DETAIL_PARAMETER_LIST = new CssClass("parameter", "div", "dl");
+ public static final CssClass MEMBER_DETAIL_PARAMETER_HEADER = new CssClass("header", "dt", "b");
+ public static final CssClass MEMBER_DETAIL_PARAMETER_ITEM = new CssClass("item", "dd");
+ public static final CssClass MEMBER_DETAIL_PARAMETER_ITEM_NAME = new CssClass("name", "code");
+ public static final CssClass MEMBER_DETAIL_PARAMETER_ITEM_SEPARATOR = new CssClass("separator");
+ public static final CssClass MEMBER_DETAIL_PARAMETER_ITEM_DESCRIPTION = new CssClass("description");
+ public static final CssClass MEMBER_DETAIL_RETURN_LIST = new CssClass("member detail return list", "div", "dl");
+ public static final CssClass MEMBER_DETAIL_RETURN_HEADER = new CssClass("member detail return header", "dt", "b");
+ public static final CssClass MEMBER_DETAIL_RETURN_ITEM = new CssClass("member detail return item", "dd");
+ public static final CssClass MEMBER_DETAIL_THROWN_LIST = new CssClass("member detail thrown list", "div", "dl");
+ public static final CssClass MEMBER_DETAIL_THROWN_HEADER = new CssClass("member detail thrown header", "dt", "b");
+ public static final CssClass MEMBER_DETAIL_THROWN_ITEM = new CssClass("member detail thrown item", "dd");
+ public static final CssClass MEMBER_DETAIL_THROWN_ITEM_NAME = new CssClass("name", "code");
+ public static final CssClass MEMBER_DETAIL_THROWN_ITEM_SEPARATOR = new CssClass("separator");
+ public static final CssClass MEMBER_DETAIL_THROWN_ITEM_DESCRIPTION = new CssClass("description");
+
+ public static final CssClass TABLE_HEADER = new CssClass("table header", "h2");
+ public static final CssClass TABLE_SUB_HEADER = new CssClass("table sub header", "h3");
+ public static final CssClass TABLE_CONTAINER = new CssClass("table container", "dl", "dd");
+
+ public static final CssClass SECTION = new CssClass("section", "div");
+ public static final CssClass SECTION_HEADER = new CssClass("section header", "h2");
+
+ public static final CssClass NAVBAR_TOP = new CssClass("navbar div top");
+ public static final CssClass NAVBAR_TOP_NAVI = new CssClass("navi");
+ public static final CssClass NAVBAR_TOP_HEADER = new CssClass("header", new String[] { "rowspan" }, new String[] { "2" });
+ public static final CssClass NAVBAR_BOTTOM = new CssClass("navbar div bottom");
+ public static final CssClass NAVBAR_BOTTOM_SPACER = new CssClass("navbar bottom spacer", "p");
+ public static final CssClass NAVBAR_ITEM_ENABLED = new CssClass("navbar item enabled");
+ public static final CssClass NAVBAR_ITEM_DISABLED = new CssClass("navbar item disabled");
+ public static final CssClass NAVBAR_ITEM_ACTIVE = new CssClass("navbar item active");
+
+ public static final CssClass TAGLET = new CssClass("taglet", "div");
+
+ public static final CssClass ABOUT_TITLE = new CssClass("about title", "h1");
+ public static final CssClass ABOUT_GENERATOR = new CssClass("about generator", "p");
+
+ public static final CssClass SOURCE = new CssClass("source body");
+ public static final CssClass SOURCE_TITLE = new CssClass("source title", "h1");
+
+ public static final CssClass DEPRECATED = new CssClass("deprecated", "span");
+ public static final CssClass DEPRECATED_INLINE = new CssClass("deprecated", "p");
+ public static final CssClass DEPRECATED_HEADER = new CssClass("deprecated header", "b");
+ public static final CssClass DEPRECATED_BODY = new CssClass("deprecated", "i");
+
+ private String name;
+ private String elementName;
+ private String innerElementName;
+ private String[] attributeNames;
+ private String[] attributeValues;
+
+ private CssClass(String name)
+ {
+ this(name, null);
+ }
+
+ private CssClass(String name, String elementName)
+ {
+ this(name, elementName, null);
+ }
+
+ private CssClass(String name, String elementName, String innerElementName)
+ {
+ this(name, elementName, innerElementName, null, null);
+ }
+
+ private CssClass(String name, String elementName, String[] attributeNames, String[] attributeValues)
+ {
+ this(name, null, null, attributeNames, attributeValues);
+ }
+
+ private CssClass(String name, String[] attributeNames, String[] attributeValues)
+ {
+ this(name, null, null, attributeNames, attributeValues);
+ }
+
+ private CssClass(String name, String elementName, String innerElementName, String[] attributeNames, String[] attributeValues)
+ {
+ this.name = name;
+ this.elementName = elementName;
+ this.innerElementName = innerElementName;
+ this.attributeNames = attributeNames;
+ this.attributeValues = attributeValues;
+ }
+
+ public String getSpanElementName()
+ {
+ if (null != this.elementName) {
+ return this.elementName;
+ }
+ else {
+ return "span";
+ }
+ }
+
+ public String getDivElementName()
+ {
+ if (null != this.elementName) {
+ return this.elementName;
+ }
+ else {
+ return "div";
+ }
+ }
+
+ public String getInnerElementName()
+ {
+ return this.innerElementName;
+ }
+
+ public String[] getAttributeNames()
+ {
+ return this.attributeNames;
+ }
+
+ public String[] getAttributeValues()
+ {
+ return this.attributeValues;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/ExternalDocSet.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/ExternalDocSet.java
new file mode 100644
index 000000000..f3b2fa8ca
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/ExternalDocSet.java
@@ -0,0 +1,187 @@
+/* gnu.classpath.tools.doclets.htmldoclet.ExternalDocSet
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.htmldoclet;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import com.sun.javadoc.ClassDoc;
+
+public class ExternalDocSet
+{
+ private String url;
+ private String packageListDir;
+ private URL docSetDirectoryURL;
+
+ public String getPackageListDir()
+ {
+ return packageListDir;
+ }
+
+ public ExternalDocSet(String url,
+ String packageListDir)
+ {
+ this.url = url;
+ this.packageListDir = packageListDir;
+ }
+
+ private Set packageNames = new HashSet();
+ private boolean javadocCompatible;
+
+ public void load(File targetDirectory)
+ throws IOException, MalformedURLException
+ {
+ if (!url.endsWith("/")) {
+ url += "/";
+ }
+
+ this.docSetDirectoryURL = new URL(targetDirectory.toURL(),
+ url);
+
+ URL packageListDirURL;
+ if (null != packageListDir) {
+ if (!packageListDir.endsWith("/")) {
+ packageListDir += "/";
+ }
+ packageListDirURL = new URL(new File(System.getProperty("user.dir")).toURL(),
+ packageListDir);
+ }
+ else {
+ packageListDirURL = docSetDirectoryURL;
+ }
+
+ URL packageListURL = new URL(packageListDirURL,
+ "package-list");
+ InputStream in = packageListURL.openStream();
+ if (null != in) {
+ readPackages(in);
+ in.close();
+ }
+ else {
+ throw new FileNotFoundException(packageListURL.toString());
+ }
+
+ URL gjdocPropertiesURL = new URL(packageListDirURL,
+ "gjdoc.properties");
+ try {
+ InputStream propertiesIn = gjdocPropertiesURL.openStream();
+ if (null != in) {
+ Properties properties = new Properties();
+ properties.load(propertiesIn);
+ propertiesIn.close();
+
+ String gjdocCompatProperty = properties.getProperty("gjdoc.compat");
+ if (null != gjdocCompatProperty) {
+ javadocCompatible = "true".equals(properties.getProperty("gjdoc.compat"));
+ }
+ else {
+ javadocCompatible = true;
+ }
+ }
+ else {
+ javadocCompatible = true;
+ }
+ }
+ catch (FileNotFoundException e) {
+ javadocCompatible = true;
+ }
+ }
+
+ public String getPackageDocURL(String packageName)
+ {
+ try {
+ URL packageURL = new URL(docSetDirectoryURL,
+ packageName.replace('.', '/'));
+ return packageURL.toString();
+ }
+ catch (MalformedURLException e) {
+ // This should not happen since we know that packageName is a
+ // proper Java identifiers, so the resulting URL can't be
+ // invalid
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getClassDocURL(String packageName, String typeName)
+ {
+ try {
+ URL fileURL = new URL(docSetDirectoryURL,
+ packageName.replace('.', '/') + "/" + typeName + ".html");
+ return fileURL.toString();
+ }
+ catch (MalformedURLException e) {
+ // This should not happen since we know that packageName and
+ // typeName are proper Java identifiers, so the resulting URL
+ // can't be invalid
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void readPackages(InputStream in)
+ throws IOException
+ {
+ BufferedReader reader
+ = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ packageNames.add(line);
+ }
+ }
+
+ public Set getPackageNames()
+ {
+ return packageNames;
+ }
+
+ public boolean isJavadocCompatible()
+ {
+ return javadocCompatible;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlDoclet.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlDoclet.java
new file mode 100644
index 000000000..5ec980634
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlDoclet.java
@@ -0,0 +1,3887 @@
+/* gnu.classpath.tools.doclets.htmldoclet.HtmlDoclet
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.htmldoclet;
+
+import gnu.classpath.tools.IOToolkit;
+
+import gnu.classpath.tools.doclets.AbstractDoclet;
+import gnu.classpath.tools.doclets.DocletConfigurationException;
+import gnu.classpath.tools.doclets.DocletOption;
+import gnu.classpath.tools.doclets.DocletOptionFile;
+import gnu.classpath.tools.doclets.DocletOptionFlag;
+import gnu.classpath.tools.doclets.DocletOptionString;
+import gnu.classpath.tools.doclets.PackageGroup;
+import gnu.classpath.tools.doclets.TagletPrinter;
+import gnu.classpath.tools.doclets.InlineTagRenderer;
+
+import gnu.classpath.tools.doclets.xmldoclet.HtmlRepairer;
+
+import gnu.classpath.tools.taglets.GnuExtendedTaglet;
+import gnu.classpath.tools.taglets.TagletContext;
+
+import gnu.classpath.tools.java2xhtml.Java2xhtml;
+
+import gnu.classpath.tools.StringToolkit;
+
+import com.sun.javadoc.*;
+import com.sun.tools.doclets.Taglet;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.net.MalformedURLException;
+
+import java.nio.charset.Charset;
+
+import java.text.DateFormat;
+import java.text.MessageFormat;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TimeZone;
+import java.util.TreeSet;
+
+public class HtmlDoclet
+ extends AbstractDoclet
+ implements InlineTagRenderer
+{
+ private static String filenameExtension = ".html";
+
+ /**
+ * Contains ExternalDocSet.
+ */
+ private List externalDocSets = new LinkedList();
+
+ /**
+ * Contains String->ExternalDocSet.
+ */
+ private Map packageNameToDocSet = new HashMap();
+
+ /**
+ * Cache for version string from resource /version.properties
+ */
+ private String docletVersion;
+
+ /**
+ * For now, do not output a help page.
+ */
+ private static final boolean outputHelpPage = false;
+
+ /**
+ * Stores the output encoding (either the one specified using
+ * -charset, or the platform default encoding).
+ */
+ private String outputCharset;
+
+ private void printNavBar(HtmlPage output, String currentPage, ClassDoc currentClass)
+ {
+ output.beginDiv(CssClass.NAVBAR_TOP);
+
+ boolean overviewLevel
+ = ("overview".equals(currentPage)
+ || "full-tree".equals(currentPage)
+ || "index".equals(currentPage)
+ || "split-index".equals(currentPage)
+ || "serialized".equals(currentPage)
+ || "deprecated".equals(currentPage)
+ || "about".equals(currentPage)
+ );
+
+ if (!isSinglePackage()) {
+ if ("overview".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Overview");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ output.beginAnchor(output.getPathToRoot() + "/overview-summary" + filenameExtension);
+ output.print("Overview");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+
+ output.print(" ");
+ }
+
+ if (!overviewLevel || isSinglePackage()) {
+ if ("package".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Package");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ String packageHref;
+ if (isSinglePackage()) {
+ packageHref = output.getPathToRoot() + "/" + getPackageURL(getSinglePackage()) + "package-summary" + filenameExtension;
+ }
+ else {
+ packageHref = "package-summary" + filenameExtension;
+ }
+ output.beginAnchor(packageHref);
+ output.print("Package");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ output.print("Package");
+ output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ }
+
+ if (optionUse.getValue() || optionLinkSource.getValue()) {
+ output.print(" ");
+
+ if (null != currentClass) {
+ if ("class".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Class");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ output.beginAnchor(currentClass.name() + filenameExtension);
+ output.print("Class");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ output.print("Class");
+ output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ }
+
+ if (optionUse.getValue()) {
+ output.print(" ");
+
+ if (null != currentClass) {
+ if ("uses".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Use");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ output.beginAnchor(currentClass.name() + "-uses" + filenameExtension);
+ output.print("Use");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ output.print("Use");
+ output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ }
+ }
+
+ if (optionLinkSource.getValue()) {
+ output.print(" ");
+
+
+ if ("source".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Source");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+
+ if (null != currentClass) {
+
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ String targetClassName = currentClass.name();
+ String targetAnchor = "";
+ if (null != currentClass.containingClass()) {
+ targetClassName = getOuterClassDoc(currentClass).name();
+ targetAnchor = "#line." + currentClass.position().line();
+ }
+ output.beginAnchor(targetClassName + "-source" + filenameExtension + targetAnchor);
+ output.print("Source");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ output.print("Source");
+ output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
+ }
+ }
+ }
+ }
+
+
+ if (!optionNoTree.getValue()) {
+ output.print(" ");
+
+ if ("full-tree".equals(currentPage)
+ || "package-tree".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Tree");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ String treeHref;
+ if (isSinglePackage() && overviewLevel) {
+ treeHref = getPackageURL(getSinglePackage()) + "tree" + filenameExtension;
+ }
+ else {
+ treeHref = "tree" + filenameExtension;
+ }
+
+ output.beginAnchor(treeHref);
+ output.print("Tree");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+ }
+
+ output.print(" ");
+
+ String indexName;
+ if (optionSplitIndex.getValue()) {
+ indexName = "alphaindex-1";
+ }
+ else {
+ indexName = "alphaindex";
+ }
+
+ if ("index".equals(currentPage) || "split-index".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Index");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ output.beginAnchor(output.getPathToRoot() + "/" + indexName + filenameExtension);
+ output.print("Index");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+
+ if (!optionNoDeprecatedList.getValue()) {
+ output.print(" ");
+
+ if ("deprecated".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Deprecated");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ output.beginAnchor(output.getPathToRoot() + "/deprecated" + filenameExtension);
+ output.print("Deprecated");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+ }
+
+ if (outputHelpPage) {
+ if (!optionNoHelp.getValue()) {
+ output.print(" ");
+
+ if ("help".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("Help");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ output.beginAnchor(output.getPathToRoot() + "/help" + filenameExtension);
+ output.print("Help");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+ }
+ }
+
+ output.print(" ");
+
+ if ("about".equals(currentPage)) {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ output.print("About");
+ output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
+ }
+ else {
+ output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ output.beginAnchor(output.getPathToRoot() + "/about" + filenameExtension);
+ output.print("About");
+ output.endAnchor();
+ output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
+ }
+
+ output.endDiv(CssClass.NAVBAR_TOP);
+ }
+
+ private void printNavBarTopRow(HtmlPage output, String currentPage, ClassDoc currentClass)
+ {
+ output.beginRow();
+ output.beginCell(CssClass.NAVBAR_TOP);
+ printNavBar(output, currentPage, currentClass);
+ output.endCell();
+ if (null != optionHeader.getValue()) {
+ output.beginCell(CssClass.NAVBAR_TOP_HEADER);
+ output.print(replaceDocRoot(output, optionHeader.getValue()));
+ output.endCell();
+ }
+ output.endRow();
+ }
+
+ private void printNavBarTopNaviCell(HtmlPage output)
+ {
+ output.beginCell(CssClass.NAVBAR_TOP_NAVI);
+ output.beginAnchor(output.getPathToRoot() + "/index" + filenameExtension, "Show in a frameset", "_top");
+ output.print("Frames");
+ output.endAnchor();
+ output.print(" | ");
+
+ output.beginAnchor(output.getFile().getName(), "Show without frames", "_top");
+ output.print("No Frames");
+ output.endAnchor();
+ output.print(" ");
+
+ output.endCell();
+ }
+
+ private void printNavBarTop(HtmlPage output, String currentPage)
+ {
+ printNavBarTop(output, currentPage, null, null, null);
+ }
+
+ private void printNavBarTop(HtmlPage output, String currentPage,
+ ClassDoc currentClass, Object prev, Object next)
+ {
+ if (!optionNoNavBar.getValue()) {
+ output.beginTable(CssClass.NAVBAR_TOP);
+ printNavBarTopRow(output, currentPage, currentClass);
+ output.beginRow();
+ if ("class".equals(currentPage)) {
+ output.beginCell(CssClass.NAVBAR_TOP_NAVI);
+ ClassDoc prevClass = (ClassDoc)prev;
+ ClassDoc nextClass = (ClassDoc)next;
+ if (null != prevClass) {
+ output.anchor(getClassDocURL(output, prevClass), "Prev Class");
+ }
+ else {
+ output.print("Prev Class");
+ }
+ output.print(" | ");
+ if (null != nextClass) {
+ output.anchor(getClassDocURL(output, nextClass), "Next Class");
+ }
+ else {
+ output.print("Next Class");
+ }
+ output.endCell();
+ }
+ else if ("split-index".equals(currentPage)) {
+ output.beginCell(CssClass.NAVBAR_TOP_NAVI);
+ Integer prevLetter = (Integer)prev;
+ Integer nextLetter = (Integer)next;
+ if (null != prevLetter) {
+ output.anchor("alphaindex-" + prevLetter + filenameExtension, "Prev Letter");
+ }
+ else {
+ output.print("Prev Letter");
+ }
+ output.print(" | ");
+ if (null != nextLetter) {
+ output.anchor("alphaindex-" + nextLetter + filenameExtension, "Next Letter");
+ }
+ else {
+ output.print("Next Letter");
+ }
+ output.endCell();
+ }
+ else {
+ output.beginCell(CssClass.NAVBAR_TOP_NAVI);
+ output.endCell();
+ }
+
+ printNavBarTopNaviCell(output);
+ output.endRow();
+
+ if ("class".equals(currentPage)) {
+ output.beginRow();
+
+ output.beginCell(CssClass.NAVBAR_TOP_NAVI);
+ output.print("Summary: ");
+
+ if (currentClass.innerClasses().length > 0) {
+ output.anchor("#summary-inner", "Nested");
+ }
+ else {
+ output.print("Nested");
+ }
+
+ output.print(" | ");
+
+ if (currentClass.fields().length > 0) {
+ output.anchor("#summary-fields", "Field");
+ }
+ else {
+ output.print("Field");
+ }
+
+ output.print(" | ");
+
+ if (currentClass.methods().length > 0) {
+ output.anchor("#summary-methods", "Method");
+ }
+ else {
+ output.print("Method");
+ }
+
+ output.print(" | ");
+
+ if (currentClass.constructors().length > 0) {
+ output.anchor("#summary-constructors", "Constr");
+ }
+ else {
+ output.print("Constr");
+ }
+
+ output.endCell();
+
+ output.beginCell(CssClass.NAVBAR_TOP_NAVI);
+ output.print("Detail: ");
+
+ if (currentClass.innerClasses().length > 0) {
+ output.anchor("#detail-inner", "Nested");
+ }
+ else {
+ output.print("Nested");
+ }
+
+ output.print(" | ");
+
+ if (currentClass.fields().length > 0) {
+ output.anchor("#detail-fields", "Field");
+ }
+ else {
+ output.print("Field");
+ }
+
+ output.print(" | ");
+
+ if (currentClass.methods().length > 0) {
+ output.anchor("#detail-methods", "Method");
+ }
+ else {
+ output.print("Method");
+ }
+
+ output.print(" | ");
+
+ if (currentClass.constructors().length > 0) {
+ output.anchor("#detail-constructors", "Constr");
+ }
+ else {
+ output.print("Constr");
+ }
+
+ output.endCell();
+ output.endRow();
+ }
+ output.endTable();
+ }
+ }
+
+ private void printNavBarTopPackage(HtmlPage output, String currentPage,
+ PackageDoc prevPackage, PackageDoc nextPackage)
+ {
+ if (!optionNoNavBar.getValue()) {
+ output.beginTable(CssClass.NAVBAR_TOP);
+ printNavBarTopRow(output, currentPage, null);
+
+ output.beginRow();
+ output.beginCell(CssClass.NAVBAR_TOP_NAVI);
+ if (null != prevPackage) {
+ output.anchor(output.getPathToRoot() + "/" + getPackageURL(prevPackage) + "package-summary" + filenameExtension, "Prev Package");
+ }
+ else {
+ output.print("Prev Package");
+ }
+ output.print(" | ");
+ if (null != nextPackage) {
+ output.anchor(output.getPathToRoot() + "/" + getPackageURL(nextPackage) + "package-summary" + filenameExtension, "Next Package");
+ }
+ else {
+ output.print("Next Package");
+ }
+ output.endCell();
+
+ printNavBarTopNaviCell(output);
+ output.endRow();
+
+ output.endTable();
+ }
+ }
+
+ private void printNavBarBottom(HtmlPage output, String currentPage)
+ {
+ printNavBarBottom(output, currentPage, null);
+ }
+
+ private void printNavBarBottom(HtmlPage output, String currentPage, ClassDoc currentClass)
+ {
+ if ("class".equals(currentPage)) {
+ String boilerplate = null;
+ Tag[] boilerplateTags = getOuterClassDoc(currentClass).tags("@boilerplate");
+ if (boilerplateTags.length > 0) {
+ boilerplate = boilerplateTags[0].text();
+ }
+ if (null != boilerplate) {
+ output.hr();
+ output.beginDiv(CssClass.CLASS_BOILERPLATE);
+ output.print(boilerplate);
+ output.endDiv(CssClass.CLASS_BOILERPLATE);
+ output.hr();
+ }
+ }
+
+ if (!optionNoNavBar.getValue()) {
+ output.beginDiv(CssClass.NAVBAR_BOTTOM_SPACER);
+ output.print(" ");
+ output.endDiv(CssClass.NAVBAR_BOTTOM_SPACER);
+ output.beginTable(CssClass.NAVBAR_BOTTOM);
+ output.beginRow();
+ output.beginCell();
+ printNavBar(output, currentPage, currentClass);
+ output.endCell();
+ if (null != optionFooter.getValue()) {
+ output.beginCell();
+ output.print(replaceDocRoot(output, optionFooter.getValue()));
+ output.endCell();
+ }
+ output.endRow();
+ output.endTable();
+ }
+
+ if (null != optionBottom.getValue()) {
+ output.hr();
+ output.print(replaceDocRoot(output, optionBottom.getValue()));
+ }
+ }
+
+ private void printPackagePageClasses(HtmlPage output, ClassDoc[] classDocs, String header)
+ {
+ if (classDocs.length > 0) {
+ output.beginDiv(CssClass.TABLE_CONTAINER);
+ output.beginTable(CssClass.PACKAGE_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
+ output.rowDiv(CssClass.TABLE_HEADER, header);
+
+ for (int i=0; i<classDocs.length; ++i) {
+ ClassDoc classDoc = classDocs[i];
+ if (classDoc.isIncluded()) {
+ output.beginRow();
+
+ output.beginCell(CssClass.PACKAGE_SUMMARY_LEFT);
+ printType(output, classDoc);
+ output.endCell();
+
+ output.beginCell(CssClass.PACKAGE_SUMMARY_RIGHT);
+ printTags(output, classDoc, classDoc.firstSentenceTags(), true);
+ output.endCell();
+ output.endRow();
+ }
+ }
+ output.endTable();
+ output.endDiv(CssClass.TABLE_CONTAINER);
+ output.print("\n");
+ }
+ }
+
+ private void printPackagesListFile()
+ throws IOException
+ {
+ PrintWriter out
+ = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(getTargetDirectory(),
+ "package-list")),
+ "UTF-8"));
+
+ PackageDoc[] packages = getRootDoc().specifiedPackages();
+ for (int i=0; i<packages.length; ++i) {
+ String packageName = packages[i].name();
+ if (packageName.length() > 0) {
+ out.println(packageName);
+ }
+ }
+
+ out.close();
+ }
+
+ private void printPackagePage(File packageDir, String pathToRoot,
+ PackageDoc packageDoc,
+ PackageDoc prevPackageDoc,
+ PackageDoc nextPackageDoc)
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(packageDir, "package-summary" + filenameExtension),
+ pathToRoot);
+
+ Set keywords = new LinkedHashSet();
+ keywords.add(packageDoc.name() + " packages");
+
+ output.beginPage(getPageTitle(packageDoc.name()), getOutputCharset(),
+ keywords, getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_PACKAGE);
+ printNavBarTopPackage(output, "package", prevPackageDoc, nextPackageDoc);
+
+ output.beginDiv(CssClass.PACKAGE_TITLE);
+ output.print("Package ");
+ if (packageDoc.name().length() > 0) {
+ output.print(packageDoc.name());
+ }
+ else {
+ output.print("&lt;Unnamed&gt;");
+ }
+ output.endDiv(CssClass.PACKAGE_TITLE);
+
+ output.beginDiv(CssClass.PACKAGE_DESCRIPTION_TOP);
+ printTags(output, packageDoc, packageDoc.firstSentenceTags(), true);
+ output.endDiv(CssClass.PACKAGE_DESCRIPTION_TOP);
+
+ printPackagePageClasses(output, packageDoc.interfaces(),
+ "Interface Summary");
+ printPackagePageClasses(output, packageDoc.ordinaryClasses(),
+ "Class Summary");
+ printPackagePageClasses(output, packageDoc.exceptions(),
+ "Exception Summary");
+ printPackagePageClasses(output, packageDoc.errors(),
+ "Error Summary");
+
+ output.anchorName("description");
+ output.beginDiv(CssClass.PACKAGE_DESCRIPTION_FULL);
+ printTags(output, packageDoc, packageDoc.inlineTags(), false);
+ output.endDiv(CssClass.PACKAGE_DESCRIPTION_FULL);
+
+ printNavBarBottom(output, "package");
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ static class TreeNode
+ implements Comparable
+ {
+ ClassDoc classDoc;
+ SortedSet children = new TreeSet();
+
+ TreeNode(ClassDoc classDoc) {
+ TreeNode.this.classDoc = classDoc;
+ }
+
+ public boolean equals(Object other)
+ {
+ return classDoc.equals(((TreeNode)other).classDoc);
+ }
+
+ public int compareTo(Object other)
+ {
+ return classDoc.compareTo(((TreeNode)other).classDoc);
+ }
+
+ public int hashCode()
+ {
+ return classDoc.hashCode();
+ }
+ }
+
+ private TreeNode addClassTreeNode(Map treeMap, ClassDoc classDoc)
+ {
+ TreeNode node = (TreeNode)treeMap.get(classDoc.qualifiedName());
+ if (null == node) {
+ node = new TreeNode(classDoc);
+ treeMap.put(classDoc.qualifiedName(), node);
+
+ ClassDoc superClassDoc = (ClassDoc)classDoc.superclass();
+ if (null != superClassDoc) {
+ TreeNode parentNode = addClassTreeNode(treeMap, superClassDoc);
+ parentNode.children.add(node);
+ }
+ }
+ return node;
+ }
+
+ private TreeNode addInterfaceTreeNode(Map treeMap, ClassDoc classDoc)
+ {
+ TreeNode node = (TreeNode)treeMap.get(classDoc.qualifiedName());
+ if (null == node) {
+ node = new TreeNode(classDoc);
+ treeMap.put(classDoc.qualifiedName(), node);
+
+ ClassDoc[] superInterfaces = classDoc.interfaces();
+ if (null != superInterfaces && superInterfaces.length > 0) {
+ for (int i=0; i<superInterfaces.length; ++i) {
+ TreeNode parentNode = addInterfaceTreeNode(treeMap, superInterfaces[i]);
+ parentNode.children.add(node);
+ }
+ }
+ else {
+ TreeNode rootNode = (TreeNode)treeMap.get("<root>");
+ if (null == rootNode) {
+ rootNode = new TreeNode(null);
+ treeMap.put("<root>", rootNode);
+ }
+ rootNode.children.add(node);
+ }
+ }
+ return node;
+ }
+
+ private void printPackageTreeRec(HtmlPage output, TreeNode node, TreeNode parentNode)
+ {
+ output.beginElement("li", "class", "node");
+ output.beginElement("div");
+ if (node.classDoc.isIncluded()) {
+ String packageName = node.classDoc.containingPackage().name();
+ if (packageName.length() > 0) {
+ output.print(packageName);
+ output.print(".");
+ }
+ output.beginSpan(CssClass.TREE_LINK);
+ printType(output, node.classDoc);
+ output.endSpan(CssClass.TREE_LINK);
+ }
+ else {
+ output.print(possiblyQualifiedName(node.classDoc));
+ }
+ ClassDoc[] interfaces = node.classDoc.interfaces();
+ ClassDoc parentClassDoc = null;
+ if (null != parentNode) {
+ parentClassDoc = parentNode.classDoc;
+ }
+ if (interfaces.length > 0
+ && !(interfaces.length == 1 && interfaces[0].equals(parentClassDoc))) {
+ if (node.classDoc.isInterface()) {
+ output.print(" (also implements ");
+ }
+ else {
+ output.print(" (implements ");
+ }
+
+ boolean firstItem = true;
+ for (int i=0; i<interfaces.length; ++i) {
+ ClassDoc implemented = interfaces[i];
+ if (!implemented.equals(parentClassDoc)) {
+ if (!firstItem) {
+ output.print(", ");
+ }
+ firstItem = false;
+ if (implemented.isIncluded()) {
+ output.print(implemented.containingPackage().name());
+ output.print(".");
+ printType(output, implemented);
+ }
+ else {
+ output.print(possiblyQualifiedName(implemented));
+ }
+ }
+ }
+ output.print(")");
+ }
+
+ output.endElement("div");
+ output.endElement("li");
+ if (!node.children.isEmpty()) {
+ output.beginElement("li", "class", "level");
+ output.beginElement("ul");
+ Iterator it = node.children.iterator();
+ while (it.hasNext()) {
+ TreeNode child = (TreeNode)it.next();
+ printPackageTreeRec(output, child, node);
+ }
+ output.endElement("ul");
+ output.endElement("li");
+ }
+ }
+
+ private void printClassTree(HtmlPage output, ClassDoc[] classDocs)
+ {
+ Map classTreeMap = new HashMap();
+
+ for (int i=0; i<classDocs.length; ++i) {
+ ClassDoc classDoc = classDocs[i];
+ if (!classDoc.isInterface()) {
+ addClassTreeNode(classTreeMap, classDoc);
+ }
+ }
+
+ TreeNode root = (TreeNode)classTreeMap.get("java.lang.Object");
+ if (null != root) {
+ output.div(CssClass.PACKAGE_TREE_SECTION_TITLE, "Class Hierarchy");
+ output.beginDiv(CssClass.PACKAGE_TREE);
+ printPackageTreeRec(output, root, null);
+ output.endDiv(CssClass.PACKAGE_TREE);
+ }
+ }
+
+ private void printInterfaceTree(HtmlPage output, ClassDoc[] classDocs)
+ {
+ Map interfaceTreeMap = new HashMap();
+
+ for (int i=0; i<classDocs.length; ++i) {
+ ClassDoc classDoc = classDocs[i];
+ if (classDoc.isInterface()) {
+ addInterfaceTreeNode(interfaceTreeMap, classDoc);
+ }
+ }
+
+ TreeNode interfaceRoot = (TreeNode)interfaceTreeMap.get("<root>");
+ if (null != interfaceRoot) {
+ Iterator it = interfaceRoot.children.iterator();
+ if (it.hasNext()) {
+ output.div(CssClass.PACKAGE_TREE_SECTION_TITLE, "Interface Hierarchy");
+ output.beginDiv(CssClass.PACKAGE_TREE);
+ while (it.hasNext()) {
+ TreeNode node = (TreeNode)it.next();
+ printPackageTreeRec(output, node, null);
+ }
+ output.endDiv(CssClass.PACKAGE_TREE);
+ }
+ }
+
+ }
+
+ private void printPackageTreePage(File packageDir, String pathToRoot, PackageDoc packageDoc)
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(packageDir,
+ "tree" + filenameExtension),
+ pathToRoot);
+ output.beginPage(getPageTitle(packageDoc.name() + " Hierarchy"),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_PACKAGE_TREE);
+ printNavBarTop(output, "package-tree");
+
+ output.div(CssClass.PACKAGE_TREE_TITLE, "Hierarchy for Package " + packageDoc.name());
+
+ ClassDoc[] classDocs = packageDoc.allClasses();
+ printClassTree(output, classDocs);
+ printInterfaceTree(output, classDocs);
+
+ printNavBarBottom(output, "package-tree");
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printFullTreePage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "tree" + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("Hierarchy"),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_FULL_TREE);
+ printNavBarTop(output, "full-tree");
+
+ output.div(CssClass.PACKAGE_TREE_TITLE, "Hierarchy for All Packages");
+
+ output.beginDiv(CssClass.FULL_TREE_PACKAGELIST);
+ output.div(CssClass.FULL_TREE_PACKAGELIST_HEADER, "Package Hierarchies:");
+ output.beginDiv(CssClass.FULL_TREE_PACKAGELIST_ITEM);
+ Set allPackages = getAllPackages();
+ Iterator it = allPackages.iterator();
+ while (it.hasNext()) {
+ PackageDoc packageDoc = (PackageDoc)it.next();
+ output.beginAnchor(getPackageURL(packageDoc) + "tree" + filenameExtension);
+ output.print(packageDoc.name());
+ output.endAnchor();
+ if (it.hasNext()) {
+ output.print(", ");
+ }
+ }
+ output.endDiv(CssClass.FULL_TREE_PACKAGELIST_ITEM);
+ output.endDiv(CssClass.FULL_TREE_PACKAGELIST);
+
+ ClassDoc[] classDocs = getRootDoc().classes();
+ printClassTree(output, classDocs);
+ printInterfaceTree(output, classDocs);
+
+ printNavBarBottom(output, "full-tree");
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printIndexEntry(HtmlPage output, Doc entry)
+ {
+ output.beginDiv(CssClass.INDEX_ENTRY);
+ output.beginDiv(CssClass.INDEX_ENTRY_KEY);
+ String anchor = null;
+ String description = null;
+ if (entry instanceof PackageDoc) {
+ output.beginAnchor(getPackageURL((PackageDoc)entry) + "package-summary" + filenameExtension);
+ output.print(entry.name());
+ output.endAnchor();
+ output.print(" - package");
+ }
+ else if (entry instanceof ClassDoc) {
+ ClassDoc classDoc = (ClassDoc)entry;
+ output.beginAnchor(getClassURL(classDoc));
+ output.print(entry.name() + getTypeParameters(classDoc));
+ output.endAnchor();
+ output.print(" - ");
+ if (entry.isInterface()) {
+ output.print("interface ");
+ }
+ else if (entry.isException()) {
+ output.print("exception ");
+ }
+ else if (entry.isError()) {
+ output.print("error ");
+ }
+ else {
+ output.print("class ");
+ }
+ String packageName = classDoc.containingPackage().name();
+ if (packageName.length() > 0) {
+ output.print(packageName);
+ output.print(".");
+ }
+ printType(output, classDoc);
+ }
+ else {
+ ProgramElementDoc memberDoc = (ProgramElementDoc)entry;
+ output.beginAnchor(getMemberDocURL(output, memberDoc));
+ output.print(entry.name());
+ if (memberDoc instanceof ExecutableMemberDoc) {
+ output.print(((ExecutableMemberDoc)memberDoc).signature());
+ }
+ output.endAnchor();
+ output.print(" - ");
+
+ if (memberDoc.isStatic()) {
+ output.print("static ");
+ }
+
+ if (entry.isConstructor()) {
+ output.print("constructor for class ");
+ }
+ else if (entry.isMethod()) {
+ output.print("method in class ");
+ }
+ else if (entry.isField()) {
+ output.print("field in class ");
+ }
+ ClassDoc containingClass = memberDoc.containingClass();
+ String packageName = containingClass.containingPackage().name();
+ if (packageName.length() > 0) {
+ output.print(packageName);
+ output.print(".");
+ }
+ printType(output, containingClass);
+ }
+ output.endDiv(CssClass.INDEX_ENTRY_KEY);
+ output.beginDiv(CssClass.INDEX_ENTRY_DESCRIPTION);
+ printTags(output, entry, entry.firstSentenceTags(), true);
+ output.endDiv(CssClass.INDEX_ENTRY_DESCRIPTION);
+ output.endDiv(CssClass.INDEX_ENTRY);
+ }
+
+ private void printFrameSetPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "index" + filenameExtension),
+ ".",
+ HtmlPage.DOCTYPE_FRAMESET);
+
+ String title = getWindowTitle();
+ output.beginPage(title, getOutputCharset(), getStylesheets());
+ output.beginElement("frameset", "cols", "20%,80%");
+
+ String contentURL;
+ if (isSinglePackage()) {
+ output.atomicElement("frame",
+ new String[] { "src", "name" },
+ new String[] { getPackageURL(getSinglePackage()) + "classes" + filenameExtension, "classes" });
+ contentURL = getPackageURL(getSinglePackage()) + "package-summary.html";
+ }
+ else {
+ output.beginElement("frameset", "rows", "25%,75%");
+ output.atomicElement("frame",
+ new String[] { "src", "name" },
+ new String[] { "all-packages" + filenameExtension, "packages" });
+ output.atomicElement("frame",
+ new String[] { "src", "name" },
+ new String[] { "all-classes" + filenameExtension, "classes" });
+ output.endElement("frameset");
+ contentURL = "overview-summary" + filenameExtension;
+ }
+ output.atomicElement("frame",
+ new String[] { "src", "name" },
+ new String[] { contentURL, "content" });
+ output.endElement("frameset");
+ output.endPage();
+ output.close();
+ }
+
+ private void printPackagesMenuPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "all-packages" + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("Package Menu"), getOutputCharset(), getStylesheets());
+ output.beginBody(CssClass.BODY_MENU_PACKAGES, false);
+
+ output.beginSpan(CssClass.PACKAGE_MENU_ENTRY);
+ output.beginAnchor("all-classes" + filenameExtension,
+ null,
+ "classes");
+ output.print("All Classes");
+ output.endAnchor();
+ output.endSpan(CssClass.PACKAGE_MENU_ENTRY);
+
+ output.div(CssClass.PACKAGE_MENU_TITLE, "Packages");
+
+ output.beginDiv(CssClass.PACKAGE_MENU_LIST);
+
+ Set packageDocs = getAllPackages();
+ Iterator it = packageDocs.iterator();
+ while (it.hasNext()) {
+ PackageDoc packageDoc = (PackageDoc)it.next();
+ output.beginSpan(CssClass.PACKAGE_MENU_ENTRY);
+ output.beginAnchor(getPackageURL(packageDoc) + "classes" + filenameExtension,
+ null,
+ "classes");
+ if (packageDoc.name().length() > 0) {
+ output.print(packageDoc.name());
+ }
+ else {
+ output.print("&lt;unnamed package&gt;");
+ }
+ output.endAnchor();
+ output.endSpan(CssClass.PACKAGE_MENU_ENTRY);
+ output.br();
+ }
+
+ output.endDiv(CssClass.PACKAGE_MENU_LIST);
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printClassMenuEntry(HtmlPage output, ClassDoc classDoc)
+ {
+ CssClass entryClass;
+ if (classDoc.isInterface()) {
+ entryClass = CssClass.CLASS_MENU_ENTRY_INTERFACE;
+ }
+ else {
+ entryClass = CssClass.CLASS_MENU_ENTRY_CLASS;
+ }
+ output.beginSpan(entryClass);
+ output.beginAnchor(getClassDocURL(output, classDoc),
+ classDoc.qualifiedTypeName(),
+ "content");
+ output.print(classDoc.name());
+ output.endAnchor();
+ output.endSpan(entryClass);
+ output.br();
+ }
+
+ private void printClassMenuSection(HtmlPage output, Collection classDocs, String header)
+ {
+ if (!classDocs.isEmpty()) {
+ output.div(CssClass.CLASS_MENU_SUBTITLE, header);
+ Iterator it = classDocs.iterator();
+ while (it.hasNext()) {
+ ClassDoc classDoc = (ClassDoc)it.next();
+ printClassMenuEntry(output, classDoc);
+ }
+ }
+ }
+
+ private void printClassMenuList(HtmlPage output, ClassDoc[] classDocs, boolean categorized)
+ {
+ output.beginDiv(CssClass.CLASS_MENU_LIST);
+
+ if (categorized) {
+ Set classes = new TreeSet();
+ Set interfaces = new TreeSet();
+ Set exceptions = new TreeSet();
+ Set errors = new TreeSet();
+
+ for (int i=0; i<classDocs.length; ++i) {
+ ClassDoc classDoc = classDocs[i];
+ if (classDoc.isInterface()) {
+ interfaces.add(classDoc);
+ }
+ else if (classDoc.isException()) {
+ exceptions.add(classDoc);
+ }
+ else if (classDoc.isError()) {
+ errors.add(classDoc);
+ }
+ else {
+ classes.add(classDoc);
+ }
+ }
+ printClassMenuSection(output, interfaces, "Interfaces");
+ printClassMenuSection(output, classes, "Classes");
+ printClassMenuSection(output, exceptions, "Exceptions");
+ printClassMenuSection(output, errors, "Errors");
+ }
+ else {
+ for (int i=0; i<classDocs.length; ++i) {
+ ClassDoc classDoc = classDocs[i];
+ if (classDoc.isIncluded()) {
+ printClassMenuEntry(output, classDoc);
+ }
+ }
+ }
+
+ output.endDiv(CssClass.CLASS_MENU_LIST);
+ }
+
+ private void printAllClassesMenuPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "all-classes" + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("Class Menu"), getOutputCharset(), getStylesheets());
+ output.beginBody(CssClass.BODY_MENU_CLASSES, false);
+
+ output.div(CssClass.CLASS_MENU_TITLE, "All Classes");
+
+ printClassMenuList(output, getRootDoc().classes(), false);
+
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printPackageClassesMenuPage(File packageDir, String pathToRoot, PackageDoc packageDoc)
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(packageDir,
+ "classes" + filenameExtension),
+ pathToRoot);
+
+ output.beginPage(getPageTitle(packageDoc.name() + " Class Menu"),
+ getOutputCharset(), getStylesheets());
+ output.beginBody(CssClass.BODY_MENU_CLASSES, false);
+
+ output.beginDiv(CssClass.CLASS_MENU_TITLE);
+ output.beginAnchor("package-summary" + filenameExtension, "", "content");
+ if (packageDoc.name().length() > 0) {
+ output.print(packageDoc.name());
+ }
+ else {
+ output.print("&lt;Unnamed&gt;");
+ }
+ output.endAnchor();
+ output.endDiv(CssClass.CLASS_MENU_TITLE);
+
+ printClassMenuList(output, packageDoc.allClasses(), true);
+
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printSplitIndex()
+ throws IOException
+ {
+ Map categorizedIndex = getCategorizedIndex();
+ Iterator it = categorizedIndex.keySet().iterator();
+ int n = 1;
+ int count = categorizedIndex.size();
+ while (it.hasNext()) {
+ Character c = (Character)it.next();
+ List classList = (List)categorizedIndex.get(c);
+ printIndexPage(n++, count, c, classList);
+ }
+ }
+
+ private void printIndexPage()
+ throws IOException
+ {
+ printIndexPage(0, 0, null, null);
+ }
+
+ private void printIndexPage(int index, int maxIndex, Character letter, List classList)
+ throws IOException
+ {
+ String pageName = "alphaindex";
+ if (null != letter) {
+ pageName += "-" + index;
+ }
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ pageName + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("Alphabetical Index"),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_INDEX);
+ if (null == letter) {
+ printNavBarTop(output, "index");
+ }
+ else {
+ printNavBarTop(output, "split-index", null,
+ (index > 1) ? new Integer(index - 1) : null,
+ (index < maxIndex) ? new Integer(index + 1) : null);
+ }
+
+ {
+ String title;
+ if (null == letter) {
+ title = "Alphabetical Index";
+ }
+ else {
+ title = "Alphabetical Index: " + letter;
+ }
+ output.div(CssClass.INDEX_TITLE, title);
+
+ if (null != letter || getCategorizedIndex().keySet().size() > 1) {
+ output.beginDiv(CssClass.INDEX_LETTERS);
+
+ Iterator it = getCategorizedIndex().keySet().iterator();
+ int n = 1;
+ while (it.hasNext()) {
+ Character c = (Character)it.next();
+ output.beginSpan(CssClass.INDEX_LETTER);
+ if (letter != null) {
+ output.beginAnchor("alphaindex-" + n + filenameExtension);
+ }
+ else {
+ output.beginAnchor("#" + c);
+ }
+ output.print(c.toString());
+ output.endAnchor();
+ output.endSpan(CssClass.INDEX_LETTER);
+ output.beginSpan(CssClass.INDEX_LETTER_SPACER);
+ output.print(" ");
+ output.endSpan(CssClass.INDEX_LETTER_SPACER);
+ ++n;
+ }
+ }
+
+ output.endDiv(CssClass.INDEX_LETTERS);
+ }
+
+ if (null != letter) {
+ printIndexCategory(output, letter, classList);
+ }
+ else {
+ Map categorizedIndex = getCategorizedIndex();
+ Iterator categoryIt = categorizedIndex.keySet().iterator();
+
+ while (categoryIt.hasNext()) {
+ letter = (Character)categoryIt.next();
+ classList = (List)categorizedIndex.get(letter);
+ output.anchorName(letter.toString());
+ printIndexCategory(output, letter, classList);
+ }
+ }
+
+ printNavBarBottom(output, "index");
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printIndexCategory(HtmlPage output, Character letter, List classList)
+ {
+ Iterator it = classList.iterator();
+
+ output.div(CssClass.INDEX_CATEGORY_HEADER, letter.toString());
+ output.beginDiv(CssClass.INDEX_CATEGORY);
+ while (it.hasNext()) {
+ Doc entry = (Doc)it.next();
+ printIndexEntry(output, entry);
+ }
+ output.endDiv(CssClass.INDEX_CATEGORY);
+ }
+
+ private void printDeprecationSummary(HtmlPage output, List docs, String header)
+ {
+ if (!docs.isEmpty()) {
+ output.beginDiv(CssClass.TABLE_CONTAINER);
+ output.beginTable(CssClass.DEPRECATION_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
+ output.rowDiv(CssClass.TABLE_HEADER, header);
+
+ Iterator it = docs.iterator();
+ while (it.hasNext()) {
+ Doc doc = (Doc)it.next();
+ output.beginRow();
+
+ output.beginCell(CssClass.DEPRECATION_SUMMARY_LEFT);
+ if (doc instanceof Type) {
+ printType(output, (Type)doc);
+ }
+ else {
+ ProgramElementDoc memberDoc = (ProgramElementDoc)doc;
+ output.beginAnchor(getMemberDocURL(output, memberDoc));
+ output.print(memberDoc.containingClass().qualifiedName());
+ output.print(".");
+ output.print(memberDoc.name());
+ if (memberDoc instanceof ExecutableMemberDoc) {
+ output.print(((ExecutableMemberDoc)memberDoc).flatSignature());
+ }
+ output.endAnchor();
+ }
+ output.beginDiv(CssClass.DEPRECATION_SUMMARY_DESCRIPTION);
+ printTags(output, doc, doc.tags("deprecated")[0].firstSentenceTags(), true);
+ output.endDiv(CssClass.DEPRECATION_SUMMARY_DESCRIPTION);
+
+ output.endCell();
+
+ output.endRow();
+ }
+ output.endTable();
+ output.endDiv(CssClass.TABLE_CONTAINER);
+ output.print("\n");
+ }
+ }
+
+
+ private void printSerializationPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "serialized-form" + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("Serialized Form"),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_DEPRECATED);
+ printNavBarTop(output, "serialized");
+
+ output.div(CssClass.SERIALIZED_TITLE, "Serialized Form");
+
+ Iterator it = getAllPackages().iterator();
+
+ while (it.hasNext()) {
+
+ PackageDoc packageDoc = (PackageDoc)it.next();
+
+ List serializableClasses = new LinkedList();
+ ClassDoc[] classes = packageDoc.allClasses();
+ for (int i=0; i<classes.length; ++i) {
+ ClassDoc classDoc = classes[i];
+ if (classDoc.isSerializable() || classDoc.isExternalizable()) {
+ serializableClasses.add(classDoc);
+ }
+ }
+
+ if (!serializableClasses.isEmpty()) {
+ output.div(CssClass.SERIALIZED_PACKAGE_HEADER, "Package " + packageDoc.name());
+
+ Iterator cit = serializableClasses.iterator();
+ while (cit.hasNext()) {
+ ClassDoc classDoc = (ClassDoc)cit.next();
+
+ output.anchorName(classDoc.qualifiedTypeName());
+
+ output.beginDiv(CssClass.SERIALIZED_CLASS_HEADER);
+ output.print("Class ");
+ printType(output, classDoc, true);
+ output.print(" extends ");
+ printType(output, classDoc.superclass());
+ output.print(" implements Serializable");
+ output.endDiv(CssClass.SERIALIZED_CLASS_HEADER);
+
+ FieldDoc serialVersionUidField = findField(classDoc, "serialVersionUID");
+ if (null != serialVersionUidField
+ && serialVersionUidField.isFinal()
+ && serialVersionUidField.isStatic()
+ && serialVersionUidField.type().typeName().equals("long")) {
+
+ String fieldValue = serialVersionUidField.constantValueExpression();
+ if (null != fieldValue) {
+ output.beginDiv(CssClass.SERIALIZED_SVUID_OUTER);
+ output.span(CssClass.SERIALIZED_SVUID_HEADER, "serialVersionUID: ");
+ output.span(CssClass.SERIALIZED_SVUID_VALUE, fieldValue);
+ output.endDiv(CssClass.SERIALIZED_SVUID_OUTER);
+ }
+ }
+ printMemberDetails(output,
+ classDoc.serializationMethods(),
+ "Serialization Methods",
+ true, null);
+ printMemberDetails(output,
+ classDoc.serializableFields(),
+ "Serialized Fields",
+ true, null);
+ }
+ }
+ }
+
+ printNavBarBottom(output, "serialized");
+
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+
+ private void printDeprecationPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "deprecated" + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("Deprecated API"),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_DEPRECATED);
+ printNavBarTop(output, "deprecated");
+
+ output.div(CssClass.DEPRECATION_TITLE, "Deprecated API");
+
+ List deprecatedInterfaces = new LinkedList();
+ List deprecatedExceptions = new LinkedList();
+ List deprecatedErrors = new LinkedList();
+ List deprecatedClasses = new LinkedList();
+ List deprecatedFields = new LinkedList();
+ List deprecatedMethods = new LinkedList();
+ List deprecatedConstructors = new LinkedList();
+
+ ClassDoc[] classDocs = getRootDoc().classes();
+ for (int i=0; i<classDocs.length; ++i) {
+ ClassDoc classDoc = classDocs[i];
+ {
+ Tag[] deprecatedTags = classDoc.tags("deprecated");
+ if (null != deprecatedTags && deprecatedTags.length > 0) {
+ if (classDoc.isInterface()) {
+ deprecatedInterfaces.add(classDoc);
+ }
+ else if (classDoc.isException()) {
+ deprecatedExceptions.add(classDoc);
+ }
+ else if (classDoc.isError()) {
+ deprecatedErrors.add(classDoc);
+ }
+ else {
+ deprecatedClasses.add(classDoc);
+ }
+ }
+ }
+ ConstructorDoc[] constructors = classDoc.constructors();
+ for (int j=0; j<constructors.length; ++j) {
+ Tag[] deprecatedTags = constructors[j].tags("deprecated");
+ if (null != deprecatedTags && deprecatedTags.length > 0) {
+ deprecatedConstructors.add(constructors[j]);
+ }
+ }
+ MethodDoc[] methods = classDoc.methods();
+ for (int j=0; j<methods.length; ++j) {
+ Tag[] deprecatedTags = methods[j].tags("deprecated");
+ if (null != deprecatedTags && deprecatedTags.length > 0) {
+ deprecatedMethods.add(methods[j]);
+ }
+ }
+ FieldDoc[] fields = classDoc.fields();
+ for (int j=0; j<fields.length; ++j) {
+ Tag[] deprecatedTags = fields[j].tags("deprecated");
+ if (null != deprecatedTags && deprecatedTags.length > 0) {
+ deprecatedFields.add(fields[j]);
+ }
+ }
+ }
+
+ if (!deprecatedInterfaces.isEmpty()
+ || !deprecatedClasses.isEmpty()
+ || !deprecatedExceptions.isEmpty()
+ || !deprecatedErrors.isEmpty()
+ || !deprecatedFields.isEmpty()
+ || !deprecatedMethods.isEmpty()
+ || !deprecatedConstructors.isEmpty()) {
+
+ output.beginDiv(CssClass.DEPRECATION_TOC);
+ output.div(CssClass.DEPRECATION_TOC_HEADER, "Contents");
+ output.beginDiv(CssClass.DEPRECATION_TOC_LIST);
+ if (!deprecatedInterfaces.isEmpty()) {
+ output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ output.anchor("#interfaces", "Deprecated Interfaces");
+ output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ }
+ if (!deprecatedClasses.isEmpty()) {
+ output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ output.anchor("#classes", "Deprecated Classes");
+ output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ }
+ if (!deprecatedExceptions.isEmpty()) {
+ output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ output.anchor("#exceptions", "Deprecated Exceptions");
+ output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ }
+ if (!deprecatedErrors.isEmpty()) {
+ output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ output.anchor("#errors", "Deprecated Errors");
+ output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ }
+ if (!deprecatedFields.isEmpty()) {
+ output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ output.anchor("#fields", "Deprecated Fields");
+ output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ }
+ if (!deprecatedMethods.isEmpty()) {
+ output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ output.anchor("#methods", "Deprecated Methods");
+ output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ }
+ if (!deprecatedConstructors.isEmpty()) {
+ output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ output.anchor("#constructors", "Deprecated Constructors");
+ output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
+ }
+ output.endDiv(CssClass.DEPRECATION_TOC_LIST);
+ output.endDiv(CssClass.DEPRECATION_TOC);
+ output.beginDiv(CssClass.DEPRECATION_LIST);
+
+ output.anchorName("interfaces");
+ printDeprecationSummary(output, deprecatedInterfaces, "Deprecated Interfaces");
+
+ output.anchorName("classes");
+ printDeprecationSummary(output, deprecatedClasses, "Deprecated Classes");
+
+ output.anchorName("exceptions");
+ printDeprecationSummary(output, deprecatedExceptions, "Deprecated Exceptions");
+
+ output.anchorName("errors");
+ printDeprecationSummary(output, deprecatedErrors, "Deprecated Errors");
+
+ output.anchorName("fields");
+ printDeprecationSummary(output, deprecatedFields, "Deprecated Fields");
+
+ output.anchorName("methods");
+ printDeprecationSummary(output, deprecatedMethods, "Deprecated Methods");
+
+ output.anchorName("constructors");
+ printDeprecationSummary(output, deprecatedConstructors, "Deprecated Constructors");
+
+ output.endDiv(CssClass.DEPRECATION_LIST);
+ }
+ else {
+ output.beginDiv(CssClass.DEPRECATION_EMPTY);
+ output.print("No deprecated classes or class members in this API.");
+ output.endDiv(CssClass.DEPRECATION_EMPTY);
+
+ }
+
+ printNavBarBottom(output, "deprecated");
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printAboutPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "about" + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("About"),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_ABOUT);
+
+ printNavBarTop(output, "about");
+
+ output.div(CssClass.ABOUT_TITLE, "About");
+
+ output.beginDiv(CssClass.ABOUT_GENERATOR);
+ output.print("Generated by ");
+ output.print("Gjdoc");
+ output.print(" HtmlDoclet ");
+ output.print(getDocletVersion());
+ output.print(", part of ");
+ output.beginAnchor("http://www.gnu.org/software/classpath/cp-tools/", "", "_top");
+ output.print("GNU Classpath Tools");
+ output.endAnchor();
+ output.print(", on ");
+ DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG,
+ DateFormat.LONG,
+ Locale.US);
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"),
+ Locale.US);
+ format.setCalendar(cal);
+ output.print(format.format(new Date()));
+ output.print(".");
+ output.endDiv(CssClass.ABOUT_GENERATOR);
+
+ printNavBarBottom(output, "about");
+
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printSourcePage(File packageDir, ClassDoc classDoc, String sourceXhtml)
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(packageDir,
+ classDoc.name() + "-source" + filenameExtension),
+ getPathToRoot(packageDir, getTargetDirectory()));
+ output.beginPage(getPageTitle("Source for " + classDoc.qualifiedTypeName()),
+ getOutputCharset(),
+ getStylesheets());
+
+ output.beginBody(CssClass.BODY_CONTENT_SOURCE);
+
+ printNavBarTop(output, "source", classDoc, null, null);
+
+ output.div(CssClass.SOURCE_TITLE, "Source for " + classDoc.qualifiedTypeName());
+ output.beginDiv(CssClass.SOURCE);
+ output.print(sourceXhtml);
+ output.endDiv(CssClass.SOURCE);
+
+ printNavBarBottom(output, "source", classDoc);
+
+ output.endBody();
+ output.endPage();
+
+ output.close();
+ }
+
+ private void printHelpPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "help" + filenameExtension),
+ ".");
+ output.beginPage(getPageTitle("Help"),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_HELP);
+
+ printNavBarTop(output, "help");
+
+ InputStream helpIn;
+ if (null != optionHelpFile.getValue()){
+ helpIn = new FileInputStream(optionHelpFile.getValue());
+ }
+ else {
+ helpIn = getClass().getResourceAsStream("/htmldoclet/help.xhtml");
+ }
+ output.insert(new InputStreamReader(helpIn, "utf-8"));
+ helpIn.close();
+
+ printNavBarBottom(output, "help");
+
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printOverviewPage()
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
+ "overview-summary" + filenameExtension),
+ ".");
+ output.beginPage(getWindowTitle(),
+ getOutputCharset(),
+ getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_OVERVIEW);
+
+ printNavBarTop(output, "overview");
+
+ String overviewHeader;
+ if (null != optionDocTitle.getValue()) {
+ overviewHeader = optionDocTitle.getValue();
+ }
+ else if (null != optionTitle.getValue()) {
+ overviewHeader = optionTitle.getValue();
+ }
+ else {
+ overviewHeader = null;
+ }
+
+ if (null != overviewHeader) {
+ output.div(CssClass.OVERVIEW_TITLE, overviewHeader);
+ }
+
+ output.beginDiv(CssClass.OVERVIEW_DESCRIPTION_TOP);
+ printTags(output, getRootDoc(), getRootDoc().firstSentenceTags(), true);
+ output.endDiv(CssClass.OVERVIEW_DESCRIPTION_TOP);
+
+ List packageGroups = getPackageGroups();
+
+ if (packageGroups.isEmpty()) {
+
+ printOverviewPackages(output, getAllPackages(),
+ "All Packages");
+ }
+ else {
+ Set otherPackages = new LinkedHashSet();
+ otherPackages.addAll(getAllPackages());
+
+ Iterator it = packageGroups.iterator();
+ while (it.hasNext()) {
+ PackageGroup packageGroup = (PackageGroup)it.next();
+ printOverviewPackages(output,
+ packageGroup.getPackages(),
+ packageGroup.getName());
+ otherPackages.removeAll(packageGroup.getPackages());
+ }
+
+ if (!otherPackages.isEmpty()) {
+ printOverviewPackages(output,
+ otherPackages,
+ "Other Packages");
+ }
+ }
+
+ output.anchorName("description");
+ output.beginDiv(CssClass.OVERVIEW_DESCRIPTION_FULL);
+ printTags(output, getRootDoc(), getRootDoc().inlineTags(), false);
+ output.endDiv(CssClass.OVERVIEW_DESCRIPTION_FULL);
+
+ printNavBarBottom(output, "overview");
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printOverviewPackages(HtmlPage output, Collection packageDocs, String header)
+ {
+ output.beginDiv(CssClass.TABLE_CONTAINER);
+ output.beginTable(CssClass.OVERVIEW_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
+ output.rowDiv(CssClass.TABLE_HEADER, header);
+
+ Iterator it = packageDocs.iterator();
+ while (it.hasNext()) {
+ PackageDoc packageDoc = (PackageDoc)it.next();
+ output.beginRow();
+
+ output.beginCell(CssClass.OVERVIEW_SUMMARY_LEFT);
+ output.beginAnchor(getPackageURL(packageDoc) + "package-summary" + filenameExtension);
+ output.print(packageDoc.name());
+ output.endAnchor();
+ output.endCell();
+
+ output.beginCell(CssClass.OVERVIEW_SUMMARY_RIGHT);
+ printTags(output, packageDoc, packageDoc.firstSentenceTags(), true);
+ output.endCell();
+ output.endRow();
+ }
+ output.endTable();
+ output.endDiv(CssClass.TABLE_CONTAINER);
+ }
+
+ private void printClassUsagePage(File packageDir, String pathToRoot, ClassDoc classDoc)
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(packageDir,
+ classDoc.name() + "-uses" + filenameExtension),
+ pathToRoot);
+ output.beginPage(getPageTitle(classDoc.name()), getOutputCharset(), getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_USES);
+ printNavBarTop(output, "uses", classDoc, null, null);
+
+ output.div(CssClass.USAGE_TITLE,
+ "Uses of " + getClassTypeName(classDoc)
+ + " " + classDoc.qualifiedName());
+
+ Map packageToUsageTypeMap = getUsageOfClass(classDoc);
+ if (null != packageToUsageTypeMap && !packageToUsageTypeMap.isEmpty()) {
+
+ Iterator packagesIterator = packageToUsageTypeMap.keySet().iterator();
+ while (packagesIterator.hasNext()) {
+ PackageDoc packageDoc = (PackageDoc)packagesIterator.next();
+
+ output.div(CssClass.USAGE_PACKAGE_TITLE, "Uses in package " + packageDoc.name());
+
+ Map usageTypeToUsersMap = (Map)packageToUsageTypeMap.get(packageDoc);
+ Iterator usageTypeIterator = usageTypeToUsersMap.keySet().iterator();
+ while (usageTypeIterator.hasNext()) {
+ UsageType usageType = (UsageType)usageTypeIterator.next();
+
+ output.beginTable(CssClass.USAGE_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
+ output.rowDiv(CssClass.USAGE_TABLE_HEADER, format("usagetype." + usageType.getId(),
+ classDoc.qualifiedName()));
+
+ Set users = (Set)usageTypeToUsersMap.get(usageType);
+ Iterator userIterator = users.iterator();
+ while (userIterator.hasNext()) {
+ Doc user = (Doc)userIterator.next();
+
+ output.beginRow();
+
+ if (user instanceof ClassDoc) {
+ output.beginCell(CssClass.USAGE_SUMMARY_LEFT);
+ output.print("class");
+ output.endCell();
+
+ output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
+ output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ printType(output, ((ClassDoc)user));
+ output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ printTags(output, ((ClassDoc)user), ((ClassDoc)user).firstSentenceTags(), true);
+ output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ output.endCell();
+ }
+ else if (user instanceof FieldDoc) {
+ FieldDoc fieldDoc = (FieldDoc)user;
+
+ output.beginCell(CssClass.USAGE_SUMMARY_LEFT);
+ printType(output, ((FieldDoc)user).type());
+ output.endCell();
+
+ output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
+ output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ printType(output, ((FieldDoc)user).containingClass());
+ output.print(".");
+ output.beginAnchor(getMemberDocURL(output, (FieldDoc)user));
+ output.print(((FieldDoc)user).name());
+ output.endAnchor();
+ output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ printTags(output, ((FieldDoc)user), ((FieldDoc)user).firstSentenceTags(), true);
+ output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ output.endCell();
+ }
+ else if (user instanceof MethodDoc) {
+ MethodDoc methodDoc = (MethodDoc)user;
+
+ output.beginCell(CssClass.USAGE_SUMMARY_LEFT);
+ printType(output, ((MethodDoc)user).returnType());
+ output.endCell();
+
+ output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
+ output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ printType(output, ((MethodDoc)user).containingClass());
+ output.print(".");
+ output.beginAnchor(getMemberDocURL(output, (MethodDoc)user));
+ output.print(((MethodDoc)user).name());
+ output.endAnchor();
+ printParameters(output, (ExecutableMemberDoc)user);
+ output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ printTags(output, ((MethodDoc)user), ((MethodDoc)user).firstSentenceTags(), true);
+ output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ output.endCell();
+ }
+ else if (user instanceof ConstructorDoc) {
+ ConstructorDoc constructorDoc = (ConstructorDoc)user;
+
+ output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
+ output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ printType(output, ((ConstructorDoc)user).containingClass());
+ output.print(".");
+ output.beginAnchor(getMemberDocURL(output, (ConstructorDoc)user));
+ output.print(((ConstructorDoc)user).name());
+ output.endAnchor();
+ printParameters(output, (ExecutableMemberDoc)user);
+ output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
+ output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ printTags(output, ((ConstructorDoc)user),
+ ((ConstructorDoc)user).firstSentenceTags(), true);
+ output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
+ output.endCell();
+ }
+
+ output.endRow();
+ }
+ output.endTable();
+ }
+ }
+ }
+ else {
+ output.div(CssClass.USAGE_EMPTY,
+ getClassTypeName(classDoc)
+ + " " + classDoc.qualifiedName() + " is not used by any class in this documentation set.");
+ }
+ printNavBarBottom(output, "uses", classDoc);
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printSuperTreeRec(HtmlPage output, ListIterator it, int level)
+ {
+ if (it.hasPrevious()) {
+ ClassDoc cd = (ClassDoc)it.previous();
+ output.beginElement("li", new String[] { "class" }, new String[] { "inheritance " + level });
+ output.beginElement("code");
+ if (it.hasPrevious()) {
+ printType(output, cd, true);
+ }
+ else {
+ output.print(cd.qualifiedName() + getTypeParameters(cd));
+ }
+ output.endElement("code");
+ output.endElement("li");
+
+ output.beginElement("li");
+
+ if (it.hasPrevious()) {
+ output.beginElement("ul", new String[] { "class" }, new String[] { "inheritance " + (level + 1) });
+ printSuperTreeRec(output, it, level + 1);
+ output.endElement("ul");
+ }
+
+ output.endElement("li");
+ }
+ }
+
+ private static boolean isSubInterface(ClassDoc classDoc, ClassDoc otherClassDoc)
+ {
+ ClassDoc[] interfaces = otherClassDoc.interfaces();
+ for (int i=0; i<interfaces.length; ++i) {
+ if (classDoc == interfaces[i]) {
+ return true;
+ }
+ else if (isSubInterface(classDoc, interfaces[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void printCommaSeparatedTypes(HtmlPage output,
+ Collection list,
+ String header,
+ CssClass cssClass)
+ {
+ if (!list.isEmpty()) {
+ output.beginDiv(cssClass);
+ output.div(CssClass.CLASS_KNOWNIMPLEMENTING_HEADER, header);
+ output.beginDiv(CssClass.CLASS_KNOWNIMPLEMENTING_ITEM);
+ Iterator it = list.iterator();
+ while (it.hasNext()) {
+ Type type = (Type)it.next();
+ printType(output, type);
+ if (it.hasNext()) {
+ output.print(", ");
+ }
+ }
+ output.endDiv(CssClass.CLASS_KNOWNIMPLEMENTING_ITEM);
+ output.endDiv(cssClass);
+ }
+ }
+
+ private void printClassPage(File packageDir, String pathToRoot,
+ ClassDoc classDoc, ClassDoc prevClassDoc, ClassDoc nextClassDoc)
+ throws IOException
+ {
+ HtmlPage output = newHtmlPage(new File(packageDir,
+ classDoc.name() + filenameExtension),
+ pathToRoot);
+ Set keywords = new LinkedHashSet();
+ {
+ keywords.add(classDoc.qualifiedName() + " class");
+ FieldDoc[] fieldDocs = classDoc.fields();
+ for (int i=0; i<fieldDocs.length; ++i) {
+ FieldDoc fieldDoc = fieldDocs[i];
+ keywords.add(fieldDoc.name());
+ }
+
+ MethodDoc[] methodDocs = classDoc.methods();
+ for (int i=0; i<methodDocs.length; ++i) {
+ MethodDoc methodDoc = methodDocs[i];
+ keywords.add(methodDoc.name() + "()");
+ }
+ }
+ String parameters = getTypeParameters(classDoc);
+
+ output.beginPage(getPageTitle(classDoc.name()), getOutputCharset(),
+ keywords, getStylesheets());
+ output.beginBody(CssClass.BODY_CONTENT_CLASS);
+ printNavBarTop(output, "class", classDoc, prevClassDoc, nextClassDoc);
+
+ output.beginDiv(CssClass.CLASS_TITLE);
+ output.div(CssClass.CLASS_TITLE_PACKAGE,
+ classDoc.containingPackage().name());
+ output.div(CssClass.CLASS_TITLE_CLASS,
+ getClassTypeName(classDoc)
+ + " " + classDoc.name()
+ + parameters);
+ output.endDiv(CssClass.CLASS_TITLE);
+
+ boolean needSep = false;
+
+ if (classDoc.isInterface()) {
+
+ InterfaceRelation relation
+ = (InterfaceRelation)getInterfaceRelations().get(classDoc);
+
+ printCommaSeparatedTypes(output,
+ relation.superInterfaces,
+ "All Superinterfaces:",
+ CssClass.CLASS_KNOWNIMPLEMENTING);
+
+ printCommaSeparatedTypes(output,
+ relation.subInterfaces,
+ "Known Subinterfaces:",
+ CssClass.CLASS_KNOWNIMPLEMENTING);
+
+ printCommaSeparatedTypes(output,
+ relation.implementingClasses,
+ "Known Implementing Classes:",
+ CssClass.CLASS_KNOWNIMPLEMENTING);
+
+ needSep = !relation.superInterfaces.isEmpty()
+ || !relation.subInterfaces.isEmpty()
+ || !relation.implementingClasses.isEmpty();
+ }
+ else {
+ needSep = true;
+
+ if (!"java.lang.Object".equals(classDoc.qualifiedName())) {
+ LinkedList superClasses = new LinkedList();
+ for (ClassDoc cd = classDoc; cd != null; cd = cd.superclass()) {
+ superClasses.add(cd);
+ }
+ output.beginDiv(CssClass.CLASS_INHERITANCETREE);
+ output.beginElement("ul", new String[] { "class" }, new String[] { "inheritance 0" });
+ printSuperTreeRec(output, superClasses.listIterator(superClasses.size()), 0);
+ output.endElement("ul");
+ output.endDiv(CssClass.CLASS_INHERITANCETREE);
+
+ if (null != classDoc.containingClass()) {
+ output.beginDiv(CssClass.CLASS_ENCLOSINGCLASS);
+ output.div(CssClass.CLASS_ENCLOSINGCLASS_HEADER, "Enclosing Class:");
+ output.beginDiv(CssClass.CLASS_ENCLOSINGCLASS_ITEM);
+ printType(output, classDoc.containingClass());
+ output.endDiv(CssClass.CLASS_ENCLOSINGCLASS_ITEM);
+ output.endDiv(CssClass.CLASS_ENCLOSINGCLASS);
+ }
+
+ Set implementedInterfaces = getImplementedInterfaces(classDoc);
+
+ printCommaSeparatedTypes(output,
+ implementedInterfaces,
+ "Implemented Interfaces:",
+ CssClass.CLASS_KNOWNIMPLEMENTING);
+
+ List knownDirectSubclasses = getKnownDirectSubclasses(classDoc);
+ if (!knownDirectSubclasses.isEmpty()) {
+ output.beginDiv(CssClass.CLASS_SUBCLASSES);
+ output.div(CssClass.CLASS_SUBCLASSES_HEADER, "Known Direct Subclasses:");
+ output.beginDiv(CssClass.CLASS_SUBCLASSES_ITEM);
+ Iterator it = knownDirectSubclasses.iterator();
+ while (it.hasNext()) {
+ printType(output, (ClassDoc)it.next());
+ if (it.hasNext()) {
+ output.print(", ");
+ }
+ }
+
+ output.endDiv(CssClass.CLASS_SUBCLASSES_ITEM);
+ output.endDiv(CssClass.CLASS_SUBCLASSES_HEADER);
+ output.endDiv(CssClass.CLASS_SUBCLASSES);
+ }
+ }
+ }
+
+ if (needSep) {
+ output.hr();
+ }
+
+ output.beginDiv(CssClass.CLASS_SYNOPSIS);
+ output.beginDiv(CssClass.CLASS_SYNOPSIS_DECLARATION);
+ output.print(getFullModifiers(classDoc) + ' ' + getClassTypeKeyword(classDoc)
+ + ' ');
+ output.beginSpan(CssClass.CLASS_SYNOPSIS_NAME);
+ if (optionLinkSource.getValue() && null != classDoc.position()) {
+ output.beginAnchor(getOuterClassDoc(classDoc).name() + "-source" + filenameExtension + "#line." + classDoc.position());
+ output.print(classDoc.name() + parameters);
+ output.endAnchor();
+ }
+ else {
+ output.print(classDoc.name() + parameters);
+ }
+ output.endSpan(CssClass.CLASS_SYNOPSIS_NAME);
+ output.endDiv(CssClass.CLASS_SYNOPSIS_DECLARATION);
+
+ if (!classDoc.isInterface()) {
+ if (null != classDoc.superclass()) {
+ output.beginDiv(CssClass.CLASS_SYNOPSIS_SUPERCLASS);
+ output.print("extends ");
+ printType(output, classDoc.superclass());
+ output.endDiv(CssClass.CLASS_SYNOPSIS_SUPERCLASS);
+ }
+ }
+
+ ClassDoc[] interfaces = classDoc.interfaces();
+ if (interfaces.length > 0) {
+ output.beginDiv(CssClass.CLASS_SYNOPSIS_IMPLEMENTS);
+ if (!classDoc.isInterface()) {
+ output.print("implements ");
+ }
+ else {
+ output.print("extends ");
+ }
+ for (int i=0; i<interfaces.length; ++i) {
+ if (i>0) {
+ output.print(", ");
+ }
+ printType(output, interfaces[i]);
+ }
+ output.endDiv(CssClass.CLASS_SYNOPSIS_IMPLEMENTS);
+ }
+ output.endDiv(CssClass.CLASS_SYNOPSIS);
+
+ output.hr();
+
+ if (!optionNoComment.getValue()) {
+ output.beginDiv(CssClass.CLASS_DESCRIPTION);
+ printTags(output, classDoc, classDoc.inlineTags(), false);
+ output.endDiv(CssClass.CLASS_DESCRIPTION);
+
+ printTaglets(output, classDoc.tags(), new HtmlTagletContext(classDoc, output, false));
+ }
+
+
+ Set implementedInterfaces = getImplementedInterfaces(classDoc);
+
+ boolean haveInheritedFields = false;
+ boolean haveInheritedMethods = false;
+ boolean haveInheritedClasses = false;
+ {
+ if (!classDoc.isInterface()) {
+ ClassDoc superClassDoc = classDoc.superclass();
+ while (null != superClassDoc
+ && (!haveInheritedFields
+ || !haveInheritedMethods
+ || !haveInheritedClasses)) {
+ if (superClassDoc.fields().length > 0) {
+ haveInheritedFields = true;
+ }
+ if (superClassDoc.methods().length > 0) {
+ haveInheritedMethods = true;
+ }
+ if (superClassDoc.innerClasses().length > 0) {
+ haveInheritedClasses = true;
+ }
+ superClassDoc = superClassDoc.superclass();
+ }
+ }
+ }
+
+ printProgramElementDocs(output, getSortedInnerClasses(classDoc),
+ "Nested Class Summary", haveInheritedClasses,
+ "summary-inner");
+
+ {
+ ClassDoc superClassDoc = classDoc.superclass();
+ while (null != superClassDoc) {
+ printInheritedMembers(output, getSortedInnerClasses(superClassDoc),
+ "Nested classes/interfaces inherited from class {0}",
+ superClassDoc);
+ superClassDoc = superClassDoc.superclass();
+ }
+ }
+
+ printProgramElementDocs(output, getSortedFields(classDoc),
+ "Field Summary", haveInheritedFields,
+ "summary-fields");
+
+ {
+ ClassDoc superClassDoc = classDoc.superclass();
+ while (null != superClassDoc) {
+ printInheritedMembers(output, getSortedFields(superClassDoc),
+ "Fields inherited from class {0}",
+ superClassDoc);
+ superClassDoc = superClassDoc.superclass();
+ }
+ }
+
+ {
+ Iterator it = implementedInterfaces.iterator();
+ while (it.hasNext()) {
+ ClassDoc implementedInterface
+ = (ClassDoc)it.next();
+ if (!"java.io.Serializable".equals(implementedInterface.qualifiedName())
+ && !"java.io.Externalizable".equals(implementedInterface.qualifiedName())) {
+ printInheritedMembers(output, getSortedFields(implementedInterface),
+ "Fields inherited from interface {0}",
+ implementedInterface);
+ }
+ }
+ }
+
+ printProgramElementDocs(output, getSortedConstructors(classDoc),
+ "Constructor Summary", false,
+ "summary-constructors");
+ printProgramElementDocs(output, getSortedMethods(classDoc),
+ "Method Summary", haveInheritedMethods,
+ "summary-methods");
+
+ if (classDoc.isInterface()) {
+ InterfaceRelation relation
+ = (InterfaceRelation)getInterfaceRelations().get(classDoc);
+ Iterator it = relation.superInterfaces.iterator();
+ while (it.hasNext()) {
+ ClassDoc superClassDoc = (ClassDoc)it.next();
+ printInheritedMembers(output, getSortedMethods(superClassDoc),
+ "Methods inherited from interface {0}",
+ superClassDoc);
+ }
+ }
+ else {
+ ClassDoc superClassDoc = classDoc.superclass();
+ while (null != superClassDoc) {
+ printInheritedMembers(output, getSortedMethods(superClassDoc),
+ "Methods inherited from class {0}",
+ superClassDoc);
+ superClassDoc = superClassDoc.superclass();
+ }
+ }
+
+ printMemberDetails(output, getSortedFields(classDoc),
+ "Field Details", false, "detail-fields");
+ printMemberDetails(output, getSortedConstructors(classDoc),
+ "Constructor Details", false, "detail-constructors");
+ printMemberDetails(output, getSortedMethods(classDoc),
+ "Method Details", false, "detail-methods");
+
+ printNavBarBottom(output, "class", classDoc);
+
+ output.endBody();
+ output.endPage();
+ output.close();
+ }
+
+ private void printInheritedMembers(HtmlPage output,
+ ProgramElementDoc[] memberDocs,
+ String headerFormat,
+ ClassDoc superclass)
+ {
+ if (memberDocs.length > 0) {
+
+ output.beginDiv(CssClass.TABLE_CONTAINER);
+ output.beginTable(CssClass.CLASS_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
+ String superclassLink;
+ if (superclass.isIncluded()) {
+ superclassLink = superclass.containingPackage().name()
+ + "." + createTypeHref(output, superclass, false);
+ }
+ else {
+ superclassLink = createTypeHref(output, superclass, true);
+ }
+ output.rowDiv(CssClass.TABLE_SUB_HEADER,
+ new MessageFormat(headerFormat).format(new Object[] {
+ superclassLink
+ }));
+
+ output.beginRow();
+ output.beginCell(CssClass.CLASS_SUMMARY_INHERITED);
+ for (int i=0; i<memberDocs.length; ++i) {
+ ProgramElementDoc memberDoc = memberDocs[i];
+ if (i > 0) {
+ output.print(", ");
+ }
+ String title = null;
+ if (memberDoc.isMethod()) {
+ title = memberDoc.name() + ((MethodDoc)memberDoc).flatSignature();
+ }
+ else if (memberDoc.isInterface()) {
+ title = "interface " + ((ClassDoc)memberDoc).qualifiedName();
+ }
+ else if (memberDoc.isClass()) {
+ title = "class " + ((ClassDoc)memberDoc).qualifiedName();
+ }
+ output.beginAnchor(getMemberDocURL(output, memberDoc), title);
+ output.beginSpan(CssClass.CLASS_SUMMARY_INHERITED_MEMBER);
+ output.print(memberDoc.name());
+ output.endSpan(CssClass.CLASS_SUMMARY_INHERITED_MEMBER);
+ output.endAnchor();
+ }
+ output.endCell();
+ output.endRow();
+ output.endTable();
+ output.endDiv(CssClass.TABLE_CONTAINER);
+ }
+ }
+
+ private void collectSpecifiedByRecursive(Set specifyingInterfaces,
+ ClassDoc classDoc,
+ MethodDoc methodDoc)
+ {
+ ClassDoc[] interfaces = classDoc.interfaces();
+ for (int i=0; i<interfaces.length; ++i) {
+ MethodDoc[] methods = interfaces[i].methods();
+ for (int j=0; j<methods.length; ++j) {
+ if (methods[j].name().equals(methodDoc.name())
+ && methods[j].signature().equals(methodDoc.signature())) {
+ specifyingInterfaces.add(methods[j]);
+ break;
+ }
+ }
+ collectSpecifiedByRecursive(specifyingInterfaces,
+ interfaces[i],
+ methodDoc);
+ }
+ }
+
+ private void printMemberDetails(HtmlPage output,
+ ProgramElementDoc[] memberDocs, String header,
+ boolean isOnSerializedPage,
+ String anchor)
+ {
+ if (memberDocs.length > 0) {
+
+ if (null != anchor) {
+ output.anchorName(anchor);
+ }
+
+ CssClass sectionClass;
+ CssClass headerClass;
+ if (isOnSerializedPage) {
+ sectionClass = CssClass.SERIALIZED_SECTION;
+ headerClass = CssClass.SERIALIZED_SECTION_HEADER;
+ }
+ else {
+ sectionClass = CssClass.SECTION;
+ headerClass = CssClass.SECTION_HEADER;
+ }
+ output.div(headerClass, header);
+ output.beginDiv(sectionClass);
+
+ for (int i=0; i<memberDocs.length; ++i) {
+ if (i>0) {
+ output.hr();
+ }
+
+ ProgramElementDoc memberDoc = memberDocs[i];
+
+ output.anchorName(getMemberAnchor(memberDoc));
+
+ output.beginDiv(CssClass.MEMBER_DETAIL);
+ output.div(CssClass.MEMBER_DETAIL_NAME, memberDoc.name());
+
+ StringBuffer synopsis = new StringBuffer();
+ int synopsisLength = 0;
+
+ if (!isOnSerializedPage || !memberDoc.isField()) {
+ String fullModifiers = getFullModifiers(memberDoc);
+ synopsis.append(fullModifiers);
+ synopsisLength += fullModifiers.length();
+
+ }
+ if (memberDoc.isMethod() || memberDoc.isField()) {
+ Type type;
+ if (memberDoc.isMethod()) {
+ type = ((MethodDoc)memberDoc).returnType();
+ }
+ else {
+ type = ((FieldDoc)memberDoc).type();
+ }
+
+ synopsis.append(" ");
+ synopsisLength ++;
+ synopsis.append(createTypeHref(output, type, false));
+ if (null != type.asClassDoc() && type.asClassDoc().isIncluded()) {
+ synopsisLength += type.asClassDoc().name().length();
+ }
+ else {
+ synopsisLength += type.qualifiedTypeName().length();
+ }
+ synopsisLength += type.dimension().length();
+ }
+
+ synopsis.append(" ");
+ synopsisLength ++;
+
+ if (optionLinkSource.getValue() && null != memberDoc.position()) {
+ ClassDoc containingClass = memberDoc.containingClass();
+ while (null != containingClass.containingClass()) {
+ containingClass = containingClass.containingClass();
+ }
+ String href = containingClass.name() + "-source" + filenameExtension + "#line." + memberDoc.position().line();
+ synopsis.append(output.createHrefString(href, memberDoc.name()));
+ }
+ else {
+ synopsis.append(memberDoc.name());
+ }
+ synopsisLength += memberDoc.name().length();
+
+ if (memberDoc.isConstructor() || memberDoc.isMethod()) {
+ //printParameters(output, (ExecutableMemberDoc)memberDoc);
+ synopsis.append("(");
+ ++ synopsisLength;
+ StringBuffer paddingLeft = new StringBuffer();
+ for (int j=0; j<synopsisLength; ++j) {
+ paddingLeft.append(' ');
+ }
+ Parameter[] parameters = ((ExecutableMemberDoc)memberDoc).parameters();
+ for (int j=0; j<parameters.length; ++j) {
+ Parameter parameter = parameters[j];
+ synopsis.append(createTypeHref(output, parameter.type(), false));
+ synopsis.append(" ");
+ synopsis.append(parameter.name());
+ if (j < parameters.length - 1) {
+ synopsis.append(",\n");
+ synopsis.append(paddingLeft);
+ }
+ }
+ synopsis.append(")");
+ ClassDoc[] exceptions = ((ExecutableMemberDoc)memberDoc).thrownExceptions();
+ if (exceptions.length > 0) {
+ synopsis.append("\n throws ");
+ for (int j=0; j<exceptions.length; ++j) {
+ ClassDoc exception = exceptions[j];
+ synopsis.append(createTypeHref(output, exception, false));
+ if (j < exceptions.length - 1) {
+ synopsis.append(",\n ");
+ }
+ }
+ }
+ }
+
+ output.beginDiv(CssClass.MEMBER_DETAIL_SYNOPSIS);
+ output.print(synopsis.toString());
+ output.endDiv(CssClass.MEMBER_DETAIL_SYNOPSIS);
+
+ output.beginDiv(CssClass.MEMBER_DETAIL_BODY);
+
+ Tag[] deprecatedTags = memberDoc.tags("deprecated");
+ if (deprecatedTags.length > 0) {
+ output.beginDiv(CssClass.DEPRECATED_INLINE);
+ output.beginSpan(CssClass.DEPRECATED_HEADER);
+ output.print("Deprecated. ");
+ output.endSpan(CssClass.DEPRECATED_HEADER);
+ output.beginSpan(CssClass.DEPRECATED_BODY);
+ }
+ for (int j=0; j<deprecatedTags.length; ++j) {
+ printTags(output, memberDoc, deprecatedTags[j].inlineTags(), true);
+ }
+ if (deprecatedTags.length > 0) {
+ output.endSpan(CssClass.DEPRECATED_BODY);
+ output.beginDiv(CssClass.DEPRECATED_INLINE);
+ }
+
+ output.beginDiv(CssClass.MEMBER_DETAIL_DESCRIPTION);
+ printTags(output, memberDoc, memberDoc.inlineTags(), false);
+ output.endDiv(CssClass.MEMBER_DETAIL_DESCRIPTION);
+
+ if (memberDoc.isConstructor() || memberDoc.isMethod()) {
+
+ if (memberDoc.isMethod()) {
+ Set specifyingInterfaces = new LinkedHashSet();
+ if (memberDoc.containingClass().isInterface()) {
+ collectSpecifiedByRecursive(specifyingInterfaces,
+ memberDoc.containingClass(),
+ (MethodDoc)memberDoc);
+ }
+ else {
+ for (ClassDoc cd = memberDoc.containingClass();
+ null != cd; cd = cd.superclass()) {
+ collectSpecifiedByRecursive(specifyingInterfaces,
+ cd,
+ (MethodDoc)memberDoc);
+ }
+ }
+
+ if (!specifyingInterfaces.isEmpty()
+ && !isOnSerializedPage) {
+ output.beginDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_LIST);
+ output.div(CssClass.MEMBER_DETAIL_SPECIFIED_BY_HEADER, "Specified by:");
+ Iterator it = specifyingInterfaces.iterator();
+ while (it.hasNext()) {
+ MethodDoc specifyingInterfaceMethod = (MethodDoc)it.next();
+ output.beginDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_ITEM);
+ output.beginAnchor(getMemberDocURL(output,
+ specifyingInterfaceMethod));
+ output.print(memberDoc.name());
+ output.endAnchor();
+ output.print(" in interface ");
+ printType(output, specifyingInterfaceMethod.containingClass());
+ output.endDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_ITEM);
+ }
+ output.endDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_LIST);
+ }
+
+ ClassDoc overriddenClassDoc = null;
+ MemberDoc specifyingSuperMethod = null;
+
+ for (ClassDoc superclassDoc = memberDoc.containingClass().superclass();
+ null != superclassDoc && null == overriddenClassDoc;
+ superclassDoc = superclassDoc.superclass()) {
+
+ MethodDoc[] methods = superclassDoc.methods();
+ for (int j=0; j<methods.length; ++j) {
+ if (methods[j].name().equals(memberDoc.name())
+ && methods[j].signature().equals(((MethodDoc)memberDoc).signature())) {
+ overriddenClassDoc = superclassDoc;
+ specifyingSuperMethod = methods[j];
+ break;
+ }
+ }
+ }
+
+ if (null != overriddenClassDoc) {
+ output.beginDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_LIST);
+ output.div(CssClass.MEMBER_DETAIL_OVERRIDDEN_HEADER, "Overrides:");
+ output.beginDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_ITEM);
+
+ output.beginAnchor(getMemberDocURL(output,
+ specifyingSuperMethod));
+ output.print(memberDoc.name());
+ output.endAnchor();
+ output.print(" in interface ");
+ printType(output, overriddenClassDoc);
+
+ output.endDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_ITEM);
+ output.endDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_LIST);
+ }
+ }
+
+ if (!optionNoComment.getValue()) {
+
+ ExecutableMemberDoc execMemberDoc
+ = (ExecutableMemberDoc)memberDoc;
+
+ if (execMemberDoc.paramTags().length > 0) {
+ output.beginDiv(CssClass.MEMBER_DETAIL_PARAMETER_LIST);
+ output.div(CssClass.MEMBER_DETAIL_PARAMETER_HEADER, "Parameters:");
+ Parameter[] parameters = execMemberDoc.parameters();
+ for (int j=0; j<parameters.length; ++j) {
+ Parameter parameter = parameters[j];
+ ParamTag[] paramTags = execMemberDoc.paramTags();
+ ParamTag paramTag = null;
+ for (int k=0; k<paramTags.length; ++k) {
+ if (paramTags[k].parameterName().equals(parameter.name())) {
+ paramTag = paramTags[k];
+ break;
+ }
+ }
+
+ if (null != paramTag) {
+ output.beginDiv(CssClass.MEMBER_DETAIL_PARAMETER_ITEM);
+ output.beginSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_NAME);
+ output.print(parameter.name());
+ output.endSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_NAME);
+ output.beginSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_SEPARATOR);
+ output.print(" - ");
+ output.endSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_SEPARATOR);
+ output.beginSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_DESCRIPTION);
+ printTags(output, execMemberDoc, paramTag.inlineTags(), false);
+ output.endSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_DESCRIPTION);
+ output.endDiv(CssClass.MEMBER_DETAIL_PARAMETER_ITEM);
+ }
+ }
+ output.endDiv(CssClass.MEMBER_DETAIL_PARAMETER_LIST);
+ }
+
+ if (execMemberDoc.isMethod()
+ && !"void".equals(((MethodDoc)execMemberDoc).returnType().typeName())) {
+
+ Tag[] returnTags = execMemberDoc.tags("return");
+ if (returnTags.length > 0) {
+ Tag returnTag = returnTags[0];
+
+ output.beginDiv(CssClass.MEMBER_DETAIL_RETURN_LIST);
+ output.div(CssClass.MEMBER_DETAIL_RETURN_HEADER, "Returns:");
+ output.beginDiv(CssClass.MEMBER_DETAIL_RETURN_ITEM);
+
+ printTags(output, execMemberDoc, returnTag.inlineTags(), false);
+
+ output.endDiv(CssClass.MEMBER_DETAIL_RETURN_ITEM);
+ output.endDiv(CssClass.MEMBER_DETAIL_RETURN_LIST);
+ }
+ }
+
+ Set thrownExceptions = getThrownExceptions(execMemberDoc);
+ boolean haveThrowsInfo = false;
+ ThrowsTag[] throwsTags = execMemberDoc.throwsTags();
+ for (int k=0; k<throwsTags.length; ++k) {
+ ThrowsTag throwsTag = throwsTags[k];
+ if (null != throwsTags[k].exception()
+ && (isUncheckedException(throwsTags[k].exception())
+ || thrownExceptions.contains(throwsTag.exception()))) {
+ haveThrowsInfo = true;
+ break;
+ }
+ }
+
+ if (haveThrowsInfo) {
+ output.beginDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
+ output.div(CssClass.MEMBER_DETAIL_THROWN_HEADER, "Throws:");
+
+ for (int k=0; k<throwsTags.length; ++k) {
+ ThrowsTag throwsTag = throwsTags[k];
+ if (null != throwsTag.exception()
+ && (isUncheckedException(throwsTag.exception())
+ || thrownExceptions.contains(throwsTag.exception()))) {
+ output.beginDiv(CssClass.MEMBER_DETAIL_THROWN_ITEM);
+ output.beginSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_NAME);
+ printType(output, throwsTags[k].exception());
+ output.endSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_NAME);
+ if (null != throwsTag) {
+ output.beginSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_SEPARATOR);
+ output.print(" - ");
+ output.endSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_SEPARATOR);
+ output.beginSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_DESCRIPTION);
+ printTags(output, execMemberDoc, throwsTag.inlineTags(), false);
+ output.endSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_DESCRIPTION);
+ }
+ output.endDiv(CssClass.MEMBER_DETAIL_THROWN_ITEM);
+ }
+ }
+ output.endDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
+ }
+ }
+ }
+
+ if (!optionNoComment.getValue()) {
+
+ if (memberDoc.isField()) {
+ FieldDoc fieldDoc = ((FieldDoc)memberDoc);
+ if (null != fieldDoc.constantValue()) {
+ output.beginDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
+ output.div(CssClass.MEMBER_DETAIL_THROWN_HEADER, "Field Value:");
+ output.div(CssClass.MEMBER_DETAIL_THROWN_ITEM,
+ fieldDoc.constantValueExpression().toString());
+ output.endDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
+ }
+ }
+
+ TagletContext context = new HtmlTagletContext(memberDoc, output, isOnSerializedPage);
+ printTaglets(output, memberDoc.tags(), context);
+ }
+
+ output.endDiv(CssClass.MEMBER_DETAIL_BODY);
+ output.endDiv(CssClass.MEMBER_DETAIL);
+ }
+ output.endDiv(sectionClass);
+ }
+ }
+
+
+ private void printParameters(HtmlPage output, ExecutableMemberDoc memberDoc)
+ {
+ Parameter[] parameters = memberDoc.parameters();
+ output.print("(");
+ for (int j=0; j<parameters.length; ++j) {
+ if (j > 0) {
+ output.print(", ");
+ }
+ printType(output, parameters[j].type());
+ output.print("&nbsp;");
+ output.print(parameters[j].name());
+ }
+ output.print(")");
+ }
+
+ private void printProgramElementDocs(HtmlPage output,
+ ProgramElementDoc[] memberDocs,
+ String header,
+ boolean forceOutputHeader,
+ String anchor)
+ {
+ if (memberDocs.length > 0 || forceOutputHeader) {
+ output.anchorName(anchor);
+ output.beginDiv(CssClass.TABLE_CONTAINER);
+ output.beginTable(CssClass.CLASS_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
+ output.rowDiv(CssClass.TABLE_HEADER, header);
+
+ for (int i=0; i<memberDocs.length; ++i) {
+ ProgramElementDoc memberDoc = memberDocs[i];
+ output.beginRow();
+
+ if (!memberDoc.isConstructor()) {
+ output.beginCell(CssClass.CLASS_SUMMARY_LEFT);
+ output.beginDiv(CssClass.CLASS_SUMMARY_LEFT_SYNOPSIS);
+ output.print(getSummaryModifiers(memberDoc) + " ");
+ if (memberDoc.isMethod()) {
+ printType(output, ((MethodDoc)memberDoc).returnType());
+ }
+ else if (memberDoc.isField()) {
+ printType(output, ((FieldDoc)memberDoc).type());
+ }
+ else if (memberDoc.isInterface()) {
+ output.print(" interface");
+ }
+ else if (memberDoc.isClass()) {
+ output.print(" class");
+ }
+ output.endDiv(CssClass.CLASS_SUMMARY_LEFT_SYNOPSIS);
+ output.endCell();
+ }
+
+ output.beginCell(CssClass.CLASS_SUMMARY_RIGHT);
+ output.beginDiv(CssClass.CLASS_SUMMARY_RIGHT_LIST);
+ output.beginDiv(CssClass.CLASS_SUMMARY_RIGHT_SYNOPSIS);
+ if (memberDoc.isClass() || memberDoc.isInterface()) {
+ output.beginAnchor(getClassDocURL(output, (ClassDoc)memberDoc));
+ }
+ else {
+ output.beginAnchor("#" + getMemberAnchor(memberDoc));
+ }
+ output.print(memberDoc.name());
+ output.endAnchor();
+ if (memberDoc.isConstructor() || memberDoc.isMethod()) {
+ printParameters(output, (ExecutableMemberDoc)memberDoc);
+ }
+ output.endDiv(CssClass.CLASS_SUMMARY_RIGHT_SYNOPSIS);
+ Tag[] firstSentenceTags;
+ Tag[] deprecatedTags = memberDoc.tags("deprecated");
+ if (deprecatedTags.length > 0) {
+ firstSentenceTags = deprecatedTags[0].firstSentenceTags();
+ }
+ else {
+ firstSentenceTags = memberDoc.firstSentenceTags();
+ }
+
+ if (null != firstSentenceTags && firstSentenceTags.length > 0) {
+ output.beginDiv(CssClass.CLASS_SUMMARY_RIGHT_DESCRIPTION);
+ if (deprecatedTags.length > 0) {
+ output.beginDiv(CssClass.DEPRECATED);
+ output.beginSpan(CssClass.DEPRECATED_HEADER);
+ output.print("Deprecated. ");
+ output.endSpan(CssClass.DEPRECATED_HEADER);
+ output.beginSpan(CssClass.DEPRECATED_BODY);
+ }
+ printTags(output, memberDoc, firstSentenceTags, true);
+ if (deprecatedTags.length > 0) {
+ output.endSpan(CssClass.DEPRECATED_BODY);
+ output.beginDiv(CssClass.DEPRECATED);
+ }
+ output.endDiv(CssClass.CLASS_SUMMARY_RIGHT_DESCRIPTION);
+ }
+ output.endDiv(CssClass.CLASS_SUMMARY_RIGHT_LIST);
+ output.endCell();
+ output.endRow();
+ }
+ output.endTable();
+ output.endDiv(CssClass.TABLE_CONTAINER);
+ }
+ }
+
+ private void printTag(final HtmlPage output,
+ HtmlRepairer repairer,
+ Tag tag, boolean firstSentence,
+ boolean inline,
+ Doc contextDoc)
+ {
+ TagletContext context = new HtmlTagletContext(contextDoc, output, false);
+ if (firstSentence) {
+ output.print(renderInlineTags(tag.firstSentenceTags(), context));
+ }
+ else {
+ output.print(renderInlineTags(tag.inlineTags(), context));
+ }
+ }
+
+ private void printTags(HtmlPage output, Doc contextDoc, Tag[] tags, boolean firstSentence)
+ {
+ printTags(output, contextDoc, tags, firstSentence, false);
+ }
+
+ private void printTags(HtmlPage output, Doc contextDoc, Tag[] tags, boolean firstSentence, boolean inline)
+ {
+ if (!optionNoComment.getValue()) {
+ output.print(renderInlineTags(tags, new HtmlTagletContext(contextDoc, output, false)));
+ }
+
+ /*
+ if (!optionNoComment.getValue()) {
+ output.print(renderInlineTags(tag.firstSentenceTags(), output));
+ HtmlRepairer repairer = new HtmlRepairer(getRootDoc(),
+ true, false,
+ null, null,
+ true);
+ for (int i=0; i<tags.length; ++i) {
+ printTag(output, repairer, tags[i], firstSentence, inline);
+ }
+ output.print(repairer.terminateText());
+ }
+ */
+ }
+
+ private String getClassDocURL(HtmlPage output, ClassDoc classDoc)
+ {
+ return output.getPathToRoot()
+ + "/"
+ + getPackageURL(classDoc.containingPackage())
+ + classDoc.name() + filenameExtension;
+ }
+
+ private String getMemberDocURL(HtmlPage output, ProgramElementDoc memberDoc)
+ {
+ ClassDoc classDoc = memberDoc.containingClass();
+ PackageDoc packageDoc = classDoc.containingPackage();
+ ExternalDocSet externalDocSet = null;
+ if (classDoc.containingPackage().name().length() > 0) {
+ externalDocSet = (ExternalDocSet)packageNameToDocSet.get(packageDoc.name());
+ }
+ StringBuffer result = new StringBuffer();
+ result.append(getClassDocURL(output, classDoc));
+ result.append('#');
+ if (null == externalDocSet) {
+ result.append(getMemberAnchor(memberDoc));
+ }
+ else {
+ result.append(getMemberAnchor(memberDoc, externalDocSet.isJavadocCompatible()));
+ }
+ return result.toString();
+ }
+
+ private void printType(HtmlPage output, Type type)
+ {
+ printType(output, type, false);
+ }
+
+ private void printType(HtmlPage output, Type type, boolean fullyQualified)
+ {
+ output.print(createTypeHref(output, type, fullyQualified));
+ }
+
+ private String createTypeHref(HtmlPage output, Type type, boolean fullyQualified)
+ {
+ ClassDoc asClassDoc = type.asClassDoc();
+ String url = null;
+ if (null != asClassDoc && asClassDoc.isIncluded()) {
+ url = getClassDocURL(output, asClassDoc);
+ }
+ else if (!type.isPrimitive()) {
+ if (type.qualifiedTypeName().length() > type.typeName().length()) {
+ String packageName = type.qualifiedTypeName();
+ packageName = packageName.substring(0, packageName.length() - type.typeName().length() - 1);
+
+ ExternalDocSet externalDocSet
+ = (ExternalDocSet)packageNameToDocSet.get(packageName);
+ if (null != externalDocSet) {
+ url = externalDocSet.getClassDocURL(packageName, type.typeName());
+ }
+ }
+ }
+
+ StringBuffer result = new StringBuffer();
+
+ if (null != url && null != asClassDoc) {
+ String parameters = getTypeParameters(asClassDoc);
+ if (fullyQualified) {
+ result.append(output.createHrefString(url,possiblyQualifiedName(asClassDoc) + parameters));
+ }
+ else {
+ StringBuffer title = new StringBuffer();
+ title.append(getClassTypeName(asClassDoc));
+ title.append(" in ");
+ title.append(asClassDoc.containingPackage().name());
+ result.append(output.createHrefString(url, asClassDoc.name() + parameters, title.toString()));
+ }
+ }
+ else {
+ result.append(possiblyQualifiedName(type));
+ }
+ result.append(type.dimension());
+ return result.toString();
+ }
+
+ private void printTaglets(final HtmlPage output, Tag[] tags, TagletContext context)
+ {
+ super.printMainTaglets(tags, context, new TagletPrinter() {
+ public void printTagletString(String tagletString) {
+ output.beginDiv(CssClass.TAGLET);
+ output.print(tagletString);
+ output.endDiv(CssClass.TAGLET);
+ }
+ });
+ }
+
+ private String getPackageURL(PackageDoc packageDoc)
+ {
+ if (packageDoc.name().length() > 0) {
+ ExternalDocSet externalDocSet = (ExternalDocSet)packageNameToDocSet.get(packageDoc.name());
+ String url;
+ if (null != externalDocSet) {
+ url = externalDocSet.getPackageDocURL(packageDoc.name());
+ }
+ else {
+ url = packageDoc.name().replace('.', '/');
+ }
+ if (!url.endsWith("/")) {
+ return url + '/';
+ }
+ else {
+ return url;
+ }
+ }
+ else {
+ return "";
+ }
+ }
+
+ private String getClassURL(ClassDoc classDoc)
+ {
+ ExternalDocSet externalDocSet = null;
+ if (classDoc.containingPackage().name().length() > 0) {
+ externalDocSet = (ExternalDocSet)packageNameToDocSet.get(classDoc.containingPackage().name());
+ }
+ if (null != externalDocSet) {
+ return externalDocSet.getClassDocURL(classDoc.containingPackage().name(),
+ classDoc.name());
+ }
+ else {
+ return getPackageURL(classDoc.containingPackage()) + classDoc.name() + filenameExtension;
+ }
+ }
+
+ protected void run()
+ throws DocletConfigurationException, IOException
+ {
+ if (optionSerialWarn.getValue()) {
+ printWarning("Option -serialwarn is currently ignored.");
+ }
+
+ if (null != optionTitle.getValue()) {
+ printWarning("Option -title is deprecated.");
+ }
+
+ if (!optionValidHtml.getValue()) {
+ printWarning("Option -validhtml hasn't been specified. Generated HTML will not validate.");
+ }
+
+
+ {
+ boolean warningEmitted = false;
+ Iterator it = externalDocSets.iterator();
+ while (it.hasNext()) {
+ ExternalDocSet externalDocSet = (ExternalDocSet)it.next();
+ printNotice("Fetching package list for external documentation set.");
+ try {
+ externalDocSet.load(getTargetDirectory());
+ if (!isJavadocCompatibleNames() && externalDocSet.isJavadocCompatible()
+ && !warningEmitted) {
+ printWarning("Linking to javadoc-compatible documentation. Generated HTML will not validate ");
+ warningEmitted = true;
+ }
+ }
+ catch (FileNotFoundException e) {
+ printWarning("Cannot fetch package list from " + externalDocSet.getPackageListDir());
+ }
+ Iterator pit = externalDocSet.getPackageNames().iterator();
+ while (pit.hasNext()) {
+ String packageName = (String)pit.next();
+ packageNameToDocSet.put(packageName, externalDocSet);
+ }
+ }
+ }
+ printNotice("Building cross-reference information...");
+ getInterfaceRelations();
+ getAllSubClasses();
+
+ printNotice("Writing overview files...");
+ printFrameSetPage();
+ if (!isSinglePackage()) {
+ printPackagesMenuPage();
+ printAllClassesMenuPage();
+ printOverviewPage();
+ if (!optionNoTree.getValue()) {
+ printNotice("Writing full tree...");
+ printFullTreePage();
+ }
+ }
+ printPackagesListFile();
+ printAboutPage();
+ if (!optionNoIndex.getValue()) {
+ printNotice("Writing index...");
+ if (!optionSplitIndex.getValue()) {
+ printIndexPage();
+ }
+ else {
+ printSplitIndex();
+ }
+ }
+ if (outputHelpPage && !optionNoHelp.getValue()) {
+ printHelpPage();
+ }
+
+ // Copy resources
+
+ File resourcesDir = new File(getTargetDirectory(),
+ "resources");
+
+ if ((resourcesDir.exists() && !resourcesDir.isDirectory())
+ || (!resourcesDir.exists() && !resourcesDir.mkdirs())) {
+ throw new IOException("Cannot create directory " + resourcesDir);
+ }
+
+ // Copy resources
+
+ String[] resourceNames = {
+ "gjdoc.js",
+ "gjdochtml-clean-layout.css",
+ "gjdochtml-clean-color1.css",
+ "inherit.png",
+ "xhtml11-target10.dtd",
+ };
+
+ for (int i=0; i<resourceNames.length; ++i) {
+ String resourceName = resourceNames[i];
+ File targetFile = new File(resourcesDir,
+ resourceName);
+ InputStream in = getClass().getResourceAsStream("/htmldoclet/" + resourceName);
+ if (in == null) {
+ in = new FileInputStream("src/resources/htmldoclet/" + resourceName);
+ }
+ FileOutputStream out = new FileOutputStream(targetFile);
+ IOToolkit.copyStream(in, out);
+ in.close();
+ out.close();
+ }
+
+ // Copy stylesheets
+
+ if (null != optionAddStylesheet.getValue()) {
+ File addStylesheetTargetFile = new File(resourcesDir,
+ "user.css");
+
+ IOToolkit.copyFile(optionAddStylesheet.getValue(),
+ addStylesheetTargetFile);
+ }
+
+ if (null != optionStylesheetFile.getValue()) {
+ File stylesheetTargetFile = new File(resourcesDir,
+ "user.css");
+
+ IOToolkit.copyFile(optionStylesheetFile.getValue(),
+ stylesheetTargetFile);
+ }
+
+ // Write gjdoc.properties
+
+ File gjdocPropertiesTargetFile = new File(getTargetDirectory(),
+ "gjdoc.properties");
+ writeGjdocProperties(gjdocPropertiesTargetFile);
+
+ /*
+ else {
+ InputStream cssIn = getClass().getResourceAsStream("/htmldoclet/gjdochtml-vanilla.css");
+ FileOutputStream cssOut = new FileOutputStream(stylesheetTargetFile);
+ IOToolkit.copyStream(cssIn, cssOut);
+ cssIn.close();
+ cssOut.close();
+ }
+ */
+
+ if (!optionNoDeprecatedList.getValue()) {
+ printDeprecationPage();
+ }
+
+ printSerializationPage();
+
+ Collection packageDocsCollection = getAllPackages();
+ PackageDoc[] packageDocs
+ = (PackageDoc[])packageDocsCollection.toArray(new PackageDoc[0]);
+
+ for (int i=0; i<packageDocs.length; ++i) {
+ PackageDoc packageDoc = packageDocs[i];
+ File packageDir = new File(getTargetDirectory(),
+ packageDoc.name().replace('.', File.separatorChar));
+ if (!packageDir.exists() && !packageDir.mkdirs()) {
+ throw new IOException("Couldn't create directory " + packageDir);
+ }
+ try {
+ List packageSourceDirs = getPackageSourceDirs(packageDoc);
+ Iterator pdIt = packageSourceDirs.iterator();
+ while (pdIt.hasNext()) {
+ File sourcePackageDir = (File)pdIt.next();
+ copyDocFiles(sourcePackageDir, packageDir);
+ }
+ }
+ catch (IOException ignore) {
+ }
+ String pathToRoot = getPathToRoot(packageDir, getTargetDirectory());
+ String packageName = packageDoc.name();
+ if (0 == packageName.length()) {
+ packageName = "<unnamed>";
+ }
+ printNotice("Writing HTML files for package " + packageName);
+ printPackagePage(packageDir, pathToRoot, packageDoc,
+ (i > 0) ? packageDocs[i - 1] : null,
+ (i < packageDocs.length - 1) ? packageDocs[i + 1] : null);
+ if (!optionNoTree.getValue()) {
+ printPackageTreePage(packageDir, pathToRoot, packageDoc);
+ }
+ printPackageClassesMenuPage(packageDir, pathToRoot, packageDoc);
+ ClassDoc[] classDocs = packageDoc.allClasses();
+ for (int j=0; j<classDocs.length; ++j) {
+ ClassDoc classDoc = classDocs[j];
+ if (classDoc.isIncluded()) {
+ printClassPage(packageDir, pathToRoot,
+ classDocs[j],
+ (j > 0) ? classDocs[j - 1] : null,
+ (j < classDocs.length - 1) ? classDocs[j + 1] : null
+ );
+ if (optionUse.getValue()) {
+ printClassUsagePage(packageDir, pathToRoot, classDocs[j]);
+ }
+ if (optionLinkSource.getValue() && null == classDoc.containingClass()) {
+ try {
+ File sourceFile = getSourceFile(classDoc);
+
+ Java2xhtml java2xhtml = new Java2xhtml();
+ Properties properties = new Properties();
+ properties.setProperty("isCodeSnippet", "true");
+ properties.setProperty("hasLineNumbers", "true");
+ java2xhtml.setProperties(properties);
+
+ StringWriter sourceBuffer = new StringWriter();
+ FileReader sourceReader = new FileReader(sourceFile);
+ IOToolkit.copyStream(sourceReader, sourceBuffer);
+ sourceReader.close();
+ String result = java2xhtml.makeHTML(sourceBuffer.getBuffer(), sourceFile.getName());
+
+ printSourcePage(packageDir,
+ classDoc,
+ result);
+ }
+ catch (IOException e) {
+ printWarning("Cannot locate source file for class " + classDoc.qualifiedTypeName());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private String getPathToRoot(File subDir, File rootDir)
+ {
+ StringBuffer result = new StringBuffer();
+ while (!subDir.equals(rootDir)) {
+ if (result.length() > 0) {
+ result.append("/");
+ }
+ subDir = subDir.getParentFile();
+ result.append("..");
+ }
+ if (0 == result.length()) {
+ result.append(".");
+ }
+ return result.toString();
+ }
+
+ private String getClassTypeName(ClassDoc classDoc)
+ {
+ if (classDoc.isInterface()) {
+ return "Interface";
+ }
+ else {
+ return "Class";
+ }
+ }
+
+ private String getClassTypeKeyword(ClassDoc classDoc)
+ {
+ if (classDoc.isInterface()) {
+ return "interface";
+ }
+ else {
+ return "class";
+ }
+ }
+
+ private String getMemberAnchor(ProgramElementDoc memberDoc)
+ {
+ return getMemberAnchor(memberDoc, isJavadocCompatibleNames());
+ }
+
+ private String getMemberAnchor(ProgramElementDoc memberDoc, boolean javadocCompatibility)
+ {
+ StringBuffer anchor = new StringBuffer();
+ anchor.append(memberDoc.name());
+ if (memberDoc.isConstructor() || memberDoc.isMethod()) {
+ if (javadocCompatibility) {
+ anchor.append(((ExecutableMemberDoc)memberDoc).signature());
+ }
+ else {
+ anchor.append(':');
+ Parameter[] parameters = ((ExecutableMemberDoc)memberDoc).parameters();
+ for (int i=0; i<parameters.length; ++i) {
+ anchor.append(parameters[i].type().typeName());
+ for (int j=0; j<parameters[i].type().dimension().length()/2; ++j) {
+ anchor.append('-');
+ }
+ if (i < parameters.length - 1) {
+ anchor.append(':');
+ }
+ }
+ }
+ }
+ return anchor.toString();
+ }
+
+ private String getFullModifiers(ProgramElementDoc memberDoc)
+ {
+ StringBuffer result = new StringBuffer();
+ if (memberDoc.isPackagePrivate()) {
+ result.append("(package private) ");
+ }
+ result.append(memberDoc.modifiers());
+ if ((memberDoc.isClass() && ((ClassDoc)memberDoc).isAbstract())
+ || (memberDoc.isMethod() && ((MethodDoc)memberDoc).isAbstract())) {
+ result.append(" abstract");
+ }
+ return result.toString();
+ }
+
+ private String getSummaryModifiers(ProgramElementDoc memberDoc)
+ {
+ StringBuffer result = new StringBuffer();
+ if (memberDoc.isPackagePrivate()) {
+ result.append("(package private) ");
+ }
+ else if (memberDoc.isPrivate()) {
+ result.append("private ");
+ }
+ else if (memberDoc.isProtected()) {
+ result.append("protected ");
+ }
+ if (memberDoc.isStatic()) {
+ result.append("static");
+ }
+ else if ((memberDoc.isClass() && ((ClassDoc)memberDoc).isAbstract())
+ || (memberDoc.isMethod() && ((MethodDoc)memberDoc).isAbstract())) {
+ result.append("abstract");
+ }
+ return result.toString();
+ }
+
+ protected DocletOption[] getOptions()
+ {
+ return options;
+ }
+
+ private DocletOptionFlag optionNoNavBar =
+ new DocletOptionFlag("-nonavbar");
+
+ private DocletOptionFlag optionNoTree =
+ new DocletOptionFlag("-notree");
+
+ private DocletOptionFlag optionNoDeprecatedList =
+ new DocletOptionFlag("-nodeprecatedlist");
+
+ private DocletOptionFlag optionNoIndex =
+ new DocletOptionFlag("-noindex");
+
+ private DocletOptionFlag optionUse =
+ new DocletOptionFlag("-use");
+
+ private DocletOptionFlag optionNoHelp =
+ new DocletOptionFlag("-nohelp");
+
+ private DocletOptionFlag optionNoComment =
+ new DocletOptionFlag("-nocomment");
+
+ private DocletOptionFlag optionSerialWarn =
+ new DocletOptionFlag("-serialwarn");
+
+ private DocletOptionFlag optionSplitIndex =
+ new DocletOptionFlag("-splitindex");
+
+ private DocletOptionString optionHeader =
+ new DocletOptionString("-header");
+
+ private DocletOptionString optionFooter =
+ new DocletOptionString("-footer");
+
+ private DocletOptionString optionBottom =
+ new DocletOptionString("-bottom");
+
+ private DocletOptionString optionWindowTitle =
+ new DocletOptionString("-windowtitle");
+
+ private DocletOptionString optionDocTitle =
+ new DocletOptionString("-doctitle");
+
+ private DocletOptionString optionTitle =
+ new DocletOptionString("-title");
+
+ private DocletOptionFile optionHelpFile =
+ new DocletOptionFile("-helpfile");
+
+ private DocletOptionFile optionStylesheetFile =
+ new DocletOptionFile("-stylesheetfile");
+
+ private DocletOptionFlag optionLinkSource =
+ new DocletOptionFlag("-linksource");
+
+ private DocletOption optionLink =
+ new DocletOption("-link") {
+
+ public int getLength()
+ {
+ return 2;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ externalDocSets.add(new ExternalDocSet(optionArr[1], null));
+ return true;
+ }
+ };
+
+ private DocletOption optionLinkOffline =
+ new DocletOption("-linkoffline") {
+
+ public int getLength()
+ {
+ return 3;
+ }
+
+ public boolean set(String[] optionArr)
+ {
+ externalDocSets.add(new ExternalDocSet(optionArr[1], optionArr[2]));
+ return true;
+ }
+ };
+
+ private DocletOptionString optionDocEncoding =
+ new DocletOptionString("-docencoding");
+
+ private DocletOptionString optionEncoding =
+ new DocletOptionString("-encoding");
+
+ private DocletOptionString optionCharset =
+ new DocletOptionString("-charset");
+
+ private DocletOptionFile optionAddStylesheet =
+ new DocletOptionFile("-addstylesheet");
+
+ private DocletOptionFlag optionValidHtml =
+ new DocletOptionFlag("-validhtml");
+
+ private DocletOptionString optionBaseUrl =
+ new DocletOptionString("-baseurl");
+
+ private DocletOption[] options =
+ {
+ optionNoNavBar,
+ optionNoTree,
+ optionNoDeprecatedList,
+ optionNoIndex,
+ optionNoHelp,
+ optionNoComment,
+ optionUse,
+ optionSplitIndex,
+ optionHeader,
+ optionFooter,
+ optionBottom,
+ optionHelpFile,
+ optionStylesheetFile,
+ optionWindowTitle,
+ optionDocTitle,
+ optionTitle,
+ optionLinkSource,
+ optionLink,
+ optionLinkOffline,
+ optionDocEncoding,
+ optionEncoding,
+ optionCharset,
+ optionAddStylesheet,
+ optionValidHtml,
+ optionBaseUrl,
+ };
+
+ static {
+ setInstance(new HtmlDoclet());
+ }
+
+ private static String replaceDocRoot(HtmlPage output, String str)
+ {
+ return StringToolkit.replace(str, "{@docRoot}", output.getPathToRoot());
+ }
+
+ private String getOutputDocEncoding()
+ {
+ String encoding = optionDocEncoding.getValue();
+
+ if (null == encoding) {
+ encoding = optionEncoding.getValue();
+ }
+
+ return encoding;
+ }
+
+ private String getOutputCharset()
+ {
+ if (null == outputCharset) {
+
+ if (null != optionCharset.getValue()) {
+ outputCharset = optionCharset.getValue();
+ }
+ else {
+ String fileEncoding = System.getProperty("file.encoding");
+ if (null != fileEncoding) {
+ try {
+ outputCharset = Charset.forName(fileEncoding).name();
+ }
+ catch (Exception ignore) {
+ }
+ }
+
+ if (null == outputCharset) {
+ printWarning("Cannot determine platform default charset, falling back to ISO-8859-1.");
+ outputCharset = "ISO-8859-1";
+ }
+ }
+ }
+ return outputCharset;
+ }
+
+ public InlineTagRenderer getInlineTagRenderer()
+ {
+ return this;
+ }
+
+ public String renderInlineTags(Tag[] tags, TagletContext context)
+ {
+ StringBuffer result = new StringBuffer();
+
+ HtmlRepairer repairer = new HtmlRepairer(getRootDoc(),
+ true, false,
+ null, null,
+ true);
+
+ for (int i=0; i<tags.length; ++i) {
+
+ Tag tag = tags[i];
+
+ if ("Text".equals(tag.name())) {
+ result.append(repairer.getWellformedHTML(tag.text()));
+ }
+ else if ("@link".equals(tag.name())) {
+ result.append(renderSeeTag((SeeTag)tag, context, false));
+ }
+ else if ("@linkplain".equals(tag.name())) {
+ result.append(renderSeeTag((SeeTag)tag, context, true));
+ }
+ else if ("@docRoot".equals(tag.name())) {
+ result.append(((HtmlTagletContext)context).getOutput().getPathToRoot());
+ }
+ else {
+ //TagletContext context = TagletContext.OVERVIEW; // FIXME
+ Taglet taglet = (Taglet)tagletMap.get(tag.name().substring(1));
+ if (null != taglet) {
+ if (taglet instanceof GnuExtendedTaglet) {
+ result.append(((GnuExtendedTaglet)taglet).toString(tag, context));
+ }
+ else {
+ result.append(taglet.toString(tag));
+ }
+ }
+ }
+ }
+ result.append(repairer.terminateText());
+ return result.toString();
+ }
+
+ public String renderSeeTag(SeeTag seeTag, TagletContext context, boolean plainFont)
+ {
+ StringBuffer result = new StringBuffer();
+
+ String href = null;
+ String label = null;
+ MemberDoc referencedMember = seeTag.referencedMember();
+ if (null != seeTag.referencedClass()) {
+
+ href = getClassDocURL(((HtmlTagletContext)context).getOutput(), seeTag.referencedClass());
+
+ Doc doc = context.getDoc();
+ ClassDoc classDoc = null;
+ if (doc.isClass() || doc.isInterface()) {
+ classDoc = (ClassDoc)doc;
+ }
+ else if (doc.isField() || doc.isMethod() || doc.isConstructor()) {
+ classDoc = ((MemberDoc)doc).containingClass();
+ }
+
+ if (null == referencedMember
+ || seeTag.referencedClass() != classDoc
+ || ((HtmlTagletContext)context).isOnSerializedPage()) {
+
+ if (!seeTag.referencedClass().isIncluded()) {
+ label = possiblyQualifiedName(seeTag.referencedClass());
+ }
+ else {
+ label = seeTag.referencedClass().typeName();
+ }
+ if (null != referencedMember) {
+ label += '.';
+ }
+ }
+ else {
+ label = "";
+ }
+
+ if (null != referencedMember) {
+ label += referencedMember.name();
+ if (referencedMember.isMethod() || referencedMember.isConstructor()) {
+ label += ((ExecutableMemberDoc)referencedMember).flatSignature();
+ }
+ href += '#' + getMemberAnchor(referencedMember);
+ }
+ else if (null != seeTag.referencedMemberName()) {
+ href = null;
+ }
+ }
+ else {
+ String referencedClassName = seeTag.referencedClassName();
+
+ if (null != referencedClassName) {
+
+ String referencedPackageName = null;
+
+ Iterator it = packageNameToDocSet.keySet().iterator();
+ while (it.hasNext()) {
+ String packageName = (String)it.next();
+ if ((null == referencedPackageName
+ || packageName.length() > referencedPackageName.length())
+ && referencedClassName.startsWith(packageName + '.')) {
+ referencedPackageName = packageName;
+ }
+ }
+
+ if (null != referencedPackageName) {
+ ExternalDocSet externalDocSet
+ = (ExternalDocSet)packageNameToDocSet.get(referencedPackageName);
+
+ String className = referencedClassName.substring(referencedPackageName.length() + 1);
+ href = externalDocSet.getClassDocURL(referencedPackageName,
+ className);
+ label = className;
+
+ String referencedMemberName = seeTag.referencedMemberName();
+
+ if (null != referencedMemberName) {
+ label += '.';
+ label += referencedMemberName;
+ href += '#' + transformReferencedMemberName(referencedMemberName,
+ externalDocSet.isJavadocCompatible());
+ }
+ else if (null != seeTag.referencedMemberName()) {
+ href = null;
+ }
+ }
+ }
+ }
+
+ if (null != seeTag.label()
+ && seeTag.label().length() > 0) {
+ label = seeTag.label();
+ }
+
+ if (null == label) {
+ label = seeTag.text();
+ if (label.startsWith("#")) {
+ label = label.substring(1);
+ }
+ else {
+ label = label.replace('#', '.');
+ }
+ label.trim();
+ }
+
+ if (null != href) {
+ result.append("<a href=\"");
+ result.append(href);
+ result.append("\">");
+ if (!plainFont) {
+ result.append("<code>");
+ }
+ result.append(label);
+ if (!plainFont) {
+ result.append("</code>");
+ }
+ result.append("</a>");
+ }
+ else {
+ if (!plainFont) {
+ result.append("<code>");
+ }
+ result.append(label);
+ if (!plainFont) {
+ result.append("</code>");
+ }
+ }
+
+ return result.toString();
+ }
+
+ protected String renderTag(String tagName, Tag[] tags, TagletContext context)
+ {
+ Doc doc = context.getDoc();
+
+ if ("see".equals(tagName)
+ && ((tags.length > 0)
+ || (doc.isClass()
+ && (((ClassDoc)doc).isSerializable()
+ || ((ClassDoc)doc).isExternalizable())))) {
+
+ StringBuffer result = new StringBuffer();
+ result.append("<dl class=\"tag list\">");
+ result.append("<dt class=\"tag section header\"><b>");
+ result.append("See Also:");
+ result.append("</b></dt>");
+
+ boolean oneLine = true;
+
+ if (oneLine) {
+ result.append("<dd>");
+ }
+
+ for (int i = 0; i < tags.length; ++i) {
+ if (oneLine) {
+ if (i > 0) {
+ result.append(", ");
+ }
+ }
+ else {
+ result.append("<dd>");
+ }
+ result.append(renderSeeTag((SeeTag)tags[i], context, false));
+ if (!oneLine) {
+ result.append("</dd>");
+ }
+ }
+
+ if ((doc instanceof ClassDoc)
+ && (((ClassDoc)doc).isSerializable() || ((ClassDoc)doc).isExternalizable())) {
+ if (tags.length > 0) {
+ result.append(", ");
+ }
+ HtmlPage output = ((HtmlTagletContext)context).getOutput();
+ result.append("<a href=\"" + output.getPathToRoot() + "/serialized-form" + filenameExtension + "#" + ((ClassDoc)doc).qualifiedName() + "\">Serialized Form</a>");
+ }
+
+ if (oneLine) {
+ result.append("</dd>");
+ }
+ result.append("</dl>");
+ return result.toString();
+ }
+ else if (tags.length > 0
+ && "serial".equals(tagName)
+ && ((HtmlTagletContext)context).isOnSerializedPage()) {
+
+ return renderInlineTags(tags[0].inlineTags(), context);
+ }
+ else {
+ return "";
+ }
+ }
+
+ private String getWindowTitle()
+ {
+ if (null == optionWindowTitle.getValue()) {
+ return "Generated API Documentation";
+ }
+ else {
+ return optionWindowTitle.getValue();
+ }
+ }
+
+ private String getPageTitle(String title)
+ {
+ if (null == optionWindowTitle.getValue()) {
+ return title;
+ }
+ else {
+ return title + " (" + optionWindowTitle.getValue() + ")";
+ }
+ }
+
+ protected String getDocletVersion()
+ {
+ if (null == docletVersion) {
+ docletVersion = gnu.classpath.Configuration.CLASSPATH_VERSION;
+ }
+ return docletVersion;
+ }
+
+ private Map getStylesheets()
+ {
+ Map sheets = new HashMap();
+ if (null != optionStylesheetFile.getValue()) {
+ sheets.put("User-specified", new String[] {
+ "resources/user.css"
+ });
+ }
+ else {
+ List cleanSheets = new LinkedList();
+ cleanSheets.add("resources/gjdochtml-clean-layout.css");
+ cleanSheets.add("resources/gjdochtml-clean-color1.css");
+ if (null != optionAddStylesheet.getValue()) {
+ cleanSheets.add("resources/user.css");
+ }
+ sheets.put("GNU Clean", cleanSheets.toArray(new String[0]));
+ }
+ return sheets;
+ }
+
+ protected boolean isSinglePackage()
+ {
+ if (getRootDoc().firstSentenceTags().length > 0) {
+ return false;
+ }
+ else if (null != optionDocTitle.getValue()
+ || null != optionTitle.getValue()) {
+ return false;
+ }
+ else {
+ return super.isSinglePackage();
+ }
+ }
+
+ private String getTypeParameters(ClassDoc classDoc)
+ {
+ String parameters = "";
+ TypeVariable[] params = classDoc.typeParameters();
+ if (params != null && params.length > 0)
+ {
+ parameters = "&lt;";
+ for (int a = 0; a < params.length; ++a)
+ {
+ parameters += params[a].typeName();
+ Type[] bounds = params[a].bounds();
+ if (bounds != null)
+ {
+ parameters += " extends ";
+ for (int b = 0; a < bounds.length; ++b)
+ {
+ parameters += bounds[a];
+ if (b != bounds.length - 1)
+ parameters += " & ";
+ }
+ }
+ if (a != params.length - 1)
+ parameters += ",";
+ }
+ parameters += "&gt;";
+ }
+ return parameters;
+ }
+
+ private String transformReferencedMemberName(String referencedMemberName,
+ boolean javadocCompatibility)
+ {
+ if (!javadocCompatibility) {
+ StringBuffer result = new StringBuffer();
+ for (int i=0; i<referencedMemberName.length(); ++i) {
+ char c = referencedMemberName.charAt(i);
+ switch (c) {
+ case '(': result.append(':'); break;
+ case ')': break;
+ case ',': result.append(':'); break;
+ case '[': result.append('-'); break;
+ case ']': break;
+ default: result.append(c); break;
+ }
+ }
+ return result.toString();
+ }
+ else {
+ return referencedMemberName;
+ }
+ }
+
+ public void writeGjdocProperties(File outputFile)
+ throws IOException
+ {
+ Properties properties = new Properties();
+ properties.setProperty("gjdoc.version", getDocletVersion());
+ properties.setProperty("gjdoc.compat", Boolean.toString(isJavadocCompatibleNames()));
+
+ FileOutputStream out = new FileOutputStream(outputFile);
+ properties.store(out, "GNU Gjdoc API Documentation Set Descriptor");
+ out.close();
+ }
+
+ public boolean isJavadocCompatibleNames()
+ {
+ return !optionValidHtml.getValue();
+ }
+
+ private HtmlPage newHtmlPage(File file,
+ String pathToRoot)
+ throws IOException
+ {
+ return new HtmlPage(file,
+ pathToRoot,
+ getOutputDocEncoding(),
+ optionBaseUrl.getValue(),
+ getTargetDirectory());
+ }
+
+ private HtmlPage newHtmlPage(File file,
+ String pathToRoot,
+ String docType)
+ throws IOException
+ {
+ return new HtmlPage(file,
+ pathToRoot,
+ getOutputDocEncoding(),
+ optionBaseUrl.getValue(),
+ getTargetDirectory(),
+ docType);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlPage.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlPage.java
new file mode 100644
index 000000000..0315cb5df
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlPage.java
@@ -0,0 +1,535 @@
+/* gnu.classpath.tools.doclets.htmldoclet.HtmlPage
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.htmldoclet;
+
+import gnu.classpath.tools.IOToolkit;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.sun.javadoc.Tag;
+
+/**
+ * Allows outputting an HTML document without having to build the
+ * document tree in-memory.
+ */
+public class HtmlPage
+{
+ private File file;
+ private PrintWriter out;
+ private String pathToRoot;
+ private String docType;
+ private String baseUrl;
+ private File rootDir;
+
+ public static final String DOCTYPE_FRAMESET = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">";
+
+ public HtmlPage(File file, String pathToRoot, String encoding, String baseUrl, File rootDir)
+ throws IOException
+ {
+ this(file, pathToRoot, encoding, baseUrl, rootDir, "<!DOCTYPE html PUBLIC \"-//gnu.org///DTD XHTML 1.1 plus Target 1.0//EN\" \"" + pathToRoot + "/resources/xhtml11-target10.dtd\">");
+ }
+
+ public HtmlPage(File file, String pathToRoot, String encoding, String baseUrl, File rootDir, String docType)
+ throws IOException
+ {
+ this.file = file;
+ OutputStream fileOut = new FileOutputStream(file);
+ Writer writer;
+ if (null != encoding) {
+ writer = new OutputStreamWriter(fileOut,
+ encoding);
+ }
+ else {
+ writer = new OutputStreamWriter(fileOut);
+ }
+ this.out = new PrintWriter(new BufferedWriter(writer));
+ this.pathToRoot = pathToRoot;
+ this.docType = docType;
+ this.baseUrl = baseUrl;
+ this.rootDir = rootDir;
+ }
+
+ public void beginElement(String elementName)
+ {
+ print('<');
+ print(elementName);
+ print('>');
+ }
+
+ public void beginElement(String elementName, String attributeName, String attributeValue)
+ {
+ print('<');
+ print(elementName);
+ print(' ');
+ print(attributeName);
+ print('=');
+ print('\"');
+ print(attributeValue);
+ print('\"');
+ print('>');
+ }
+
+ public void beginElement(String elementName, String[] attributeNames, String[] attributeValues)
+ {
+ print('<');
+ print(elementName);
+ for (int i=0; i<attributeNames.length; ++i) {
+ if (null != attributeValues[i]) {
+ print(' ');
+ print(attributeNames[i]);
+ print('=');
+ print('\"');
+ print(attributeValues[i]);
+ print('\"');
+ }
+ }
+ print('>');
+ }
+
+ public void beginElement(String elementName, String attributeName, String attributeValue, String[] attributeNames, String[] attributeValues)
+ {
+ print('<');
+ print(elementName);
+ print(' ');
+ print(attributeName);
+ print('=');
+ print('\"');
+ print(attributeValue);
+ print('\"');
+ if (null != attributeNames) {
+ for (int i=0; i<attributeNames.length; ++i) {
+ if (null != attributeValues[i]) {
+ print(' ');
+ print(attributeNames[i]);
+ print('=');
+ print('\"');
+ print(attributeValues[i]);
+ print('\"');
+ }
+ }
+ }
+ print('>');
+ }
+
+ public void atomicElement(String elementName)
+ {
+ print('<');
+ print(elementName);
+ print("/>");
+ }
+
+ public void atomicElement(String elementName, String attributeName, String attributeValue)
+ {
+ print('<');
+ print(elementName);
+ print(' ');
+ print(attributeName);
+ print('=');
+ print('\"');
+ print(attributeValue);
+ print('\"');
+ print("/>");
+ }
+
+ public void atomicElement(String elementName, String[] attributeNames, String[] attributeValues)
+ {
+ print('<');
+ print(elementName);
+ for (int i=0; i<attributeNames.length; ++i) {
+ if (null != attributeValues[i]) {
+ print(' ');
+ print(attributeNames[i]);
+ print('=');
+ print('\"');
+ print(attributeValues[i]);
+ print('\"');
+ }
+ }
+ print("/>");
+ }
+
+
+ public void endElement(String elementName)
+ {
+ print("</");
+ print(elementName);
+ print('>');
+ }
+
+
+ public void beginDiv(CssClass cssClass)
+ {
+ String[] divAttributeNames = cssClass.getAttributeNames();
+ String[] divAttributeValues = cssClass.getAttributeValues();
+ if (null == divAttributeNames) {
+ divAttributeNames = new String[0];
+ }
+ if (null == divAttributeValues) {
+ divAttributeValues = new String[0];
+ }
+
+ String[] attributeNames = new String[1 + divAttributeNames.length];
+ String[] attributeValues = new String[1 + divAttributeValues.length];
+
+ System.arraycopy(divAttributeNames, 0, attributeNames, 1, divAttributeNames.length);
+ System.arraycopy(divAttributeValues, 0, attributeValues, 1, divAttributeNames.length);
+
+ attributeNames[0] = "class";
+ attributeValues[0] = cssClass.getName();
+
+ beginElement(cssClass.getDivElementName(), attributeNames, attributeValues);
+ if (null != cssClass.getInnerElementName()) {
+ beginElement(cssClass.getInnerElementName());
+ }
+ }
+
+ public void endDiv(CssClass cssClass)
+ {
+ if (null != cssClass.getInnerElementName()) {
+ endElement(cssClass.getInnerElementName());
+ }
+ endElement(cssClass.getDivElementName());
+ }
+
+ public void beginSpan(CssClass cssClass)
+ {
+ beginElement(cssClass.getSpanElementName(), "class", cssClass.getName());
+ }
+
+ public void endSpan(CssClass cssClass)
+ {
+ endElement(cssClass.getSpanElementName());
+ }
+
+ public void hr()
+ {
+ atomicElement("hr");
+ }
+
+ public void br()
+ {
+ atomicElement("br");
+ }
+
+ public void print(String text)
+ {
+ out.print(text);
+ }
+
+ public void print(char c)
+ {
+ out.print(c);
+ }
+
+ public void div(CssClass cssClass, String contents)
+ {
+ beginDiv(cssClass);
+ print(contents);
+ endDiv(cssClass);
+ }
+
+ public void span(CssClass cssClass, String contents)
+ {
+ beginSpan(cssClass);
+ print(contents);
+ endSpan(cssClass);
+ }
+
+ public void beginPage(String title, String charset, Map stylesheets)
+ throws IOException
+ {
+ beginPage(title, charset, Collections.EMPTY_SET, stylesheets);
+ }
+
+ public void beginPage(String title, String charset,
+ Collection keywords, Map stylesheets)
+ throws IOException
+ {
+ print("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\n");
+ print(docType);
+ print("<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">");
+ beginElement("head");
+ beginElement("title");
+ print(title);
+ endElement("title");
+ if (null != baseUrl && baseUrl.length() > 0) {
+ StringBuffer url = new StringBuffer();
+ url.append(baseUrl);
+ if ('/' == url.charAt(url.length() - 1)) {
+ url.delete(url.length() - 1, url.length());
+ }
+ url.append(file.getCanonicalPath().substring(rootDir.getCanonicalPath().length()));
+ atomicElement("base",
+ new String[] { "href" },
+ new String[] { url.toString() });
+ }
+ beginElement("script",
+ new String[] { "src", "type" },
+ new String[] { pathToRoot + "/resources/gjdoc.js", "text/javascript" });
+ print("<!-- this comment required for konqueror 3.2.2 -->");
+ endElement("script");
+ atomicElement("meta",
+ new String[] { "http-equiv", "content" },
+ new String[] { "Content-Type", "text/html; charset=" + charset });
+ atomicElement("meta",
+ new String[] { "name", "content" },
+ new String[] { "generator", "GNU Gjdoc Standard Doclet" });
+ Iterator keywordIt = keywords.iterator();
+ while (keywordIt.hasNext()) {
+ String keyword = (String)keywordIt.next();
+ atomicElement("meta",
+ new String[] { "name", "content" },
+ new String[] { "keywords", keyword });
+ }
+
+ Iterator cssIt = stylesheets.keySet().iterator();
+ while (cssIt.hasNext()) {
+ String sheetName = (String)cssIt.next();
+ String[] sheetFiles = (String[])stylesheets.get(sheetName);
+
+ for (int i=0; i<sheetFiles.length; ++i) {
+ String sheetFile = sheetFiles[i];
+ atomicElement("link",
+ new String[] { "rel", "type", "href", "title" },
+ new String[] { "stylesheet", "text/css",
+ pathToRoot + "/" + sheetFile, sheetName });
+ }
+ }
+
+ endElement("head");
+ }
+
+ public void endPage()
+ {
+ endElement("html");
+ }
+
+ public void close()
+ {
+ out.close();
+ }
+
+ public void beginTable(CssClass cssClass)
+ {
+ beginElement("table", "class", cssClass.getName());
+ }
+
+ public void beginTable(CssClass cssClass, String[] attributeNames, String[] attributeValues)
+ {
+ beginElement("table", "class", cssClass.getName(), attributeNames, attributeValues);
+ }
+
+ public void beginRow()
+ {
+ beginElement("tr");
+ }
+
+ public void beginRow(CssClass cssClass)
+ {
+ beginElement("tr", "class", cssClass.getName(), cssClass.getAttributeNames(), cssClass.getAttributeValues());
+ }
+
+ public void beginRow(String attribute, String value)
+ {
+ beginElement("tr", attribute, value);
+ }
+
+ public void beginCell()
+ {
+ beginElement("td");
+ }
+
+ public void beginCell(String attribute, String value)
+ {
+ beginElement("td", attribute, value);
+ }
+
+ public void beginCell(CssClass cssClass)
+ {
+ beginElement("td", "class", cssClass.getName(), cssClass.getAttributeNames(), cssClass.getAttributeValues());
+ }
+
+ public void endCell()
+ {
+ endElement("td");
+ }
+
+ public void cell(CssClass cssClass, String contents)
+ {
+ beginCell(cssClass);
+ print(contents);
+ endCell();
+ }
+
+ public void endRow()
+ {
+ endElement("tr");
+ }
+
+ public void rowDiv(CssClass cssClass, String contents)
+ {
+ beginRow(cssClass);
+ beginCell("colspan", "2");
+ beginDiv(cssClass);
+ print(contents);
+ endDiv(cssClass);
+ endCell();
+ endRow();
+ }
+
+ public void endTable()
+ {
+ endElement("table");
+ }
+
+ public void beginAnchor(String href)
+ {
+ beginElement("a", "href", href);
+ }
+
+ public void beginAnchor(String href, String title)
+ {
+ beginElement("a",
+ new String[] { "href", "title" },
+ new String[] { href, title });
+ }
+
+ public void beginAnchor(String href, String title, String target)
+ {
+ beginElement("a",
+ new String[] { "href", "title", "target" },
+ new String[] { href, title, target });
+ }
+
+ public void endAnchor()
+ {
+ endElement("a");
+ }
+
+ public void anchor(String href, String label)
+ {
+ beginAnchor(href);
+ print(label);
+ endAnchor();
+ }
+
+ public void anchorName(String name)
+ {
+ atomicElement("a", new String[] { "name", "id" }, new String[] { name, name });
+ }
+
+ public String getPathToRoot()
+ {
+ return pathToRoot;
+ }
+
+ public void beginBody(CssClass cssClass)
+ {
+ beginBody(cssClass, true);
+ }
+
+ public void beginBody(CssClass cssClass, boolean setTitle)
+ {
+ if (setTitle) {
+ beginElement("body",
+ new String[] { "class", "onload" },
+ new String[] { cssClass.getName(), "if(parent.contentPageLoaded)parent.contentPageLoaded(document.title)" }
+ );
+ }
+ else {
+ beginElement("body",
+ new String[] { "class", "onload" },
+ new String[] { cssClass.getName(), "if(parent.contentPageLoaded)parent.contentPageLoaded()" }
+ );
+ }
+ }
+
+ public void endBody()
+ {
+ endElement("body");
+ }
+
+ public void insert(Reader in)
+ throws IOException
+ {
+ IOToolkit.copyStream(in, out);
+ }
+
+ public String createHrefString(String url, String content)
+ {
+ return createHrefString(url, content, null);
+ }
+
+ public String createHrefString(String url, String content, String title)
+ {
+ StringBuffer result = new StringBuffer();
+ result.append("<a href=\"");
+ result.append(url);
+ result.append("\"");
+ if (null != title) {
+ result.append(" title=\"");
+ result.append(title);
+ result.append("\"");
+ }
+ result.append(">");
+ result.append(content);
+ result.append("</a>");
+ return result.toString();
+ }
+
+ public File getFile()
+ {
+ return this.file;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlTagletContext.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlTagletContext.java
new file mode 100644
index 000000000..7b8961361
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/htmldoclet/HtmlTagletContext.java
@@ -0,0 +1,65 @@
+/* gnu.classpath.tools.doclets.htmldoclet.HtmlTagletContext
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.htmldoclet;
+
+import com.sun.javadoc.Doc;
+import gnu.classpath.tools.taglets.TagletContext;
+
+public class HtmlTagletContext
+ extends TagletContext
+{
+ private HtmlPage output;
+ private boolean isOnSerializedPage;
+
+ public HtmlTagletContext(Doc doc, HtmlPage output, boolean isOnSerializedPage)
+ {
+ super(doc);
+ this.output = output;
+ this.isOnSerializedPage = isOnSerializedPage;
+ }
+
+ public HtmlPage getOutput()
+ {
+ return output;
+ }
+
+ public boolean isOnSerializedPage()
+ {
+ return isOnSerializedPage;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver.java
new file mode 100644
index 000000000..29a9e0906
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver.java
@@ -0,0 +1,2451 @@
+/* gnu.classpath.tools.doclets.xmldoclet.Driver
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet;
+
+import com.sun.javadoc.*;
+import java.io.*;
+
+import com.sun.tools.doclets.Taglet;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import java.text.DateFormat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.TreeSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import gnu.classpath.tools.gjdoc.TemporaryStore;
+import gnu.classpath.tools.gjdoc.GjdocPackageDoc;
+
+import gnu.classpath.tools.doclets.PackageGroup;
+import gnu.classpath.tools.doclets.PackageMatcher;
+import gnu.classpath.tools.doclets.InvalidPackageWildcardException;
+
+import gnu.classpath.tools.doclets.xmldoclet.doctranslet.DocTranslet;
+import gnu.classpath.tools.doclets.xmldoclet.doctranslet.DocTransletOptions;
+
+import gnu.classpath.tools.taglets.AuthorTaglet;
+import gnu.classpath.tools.taglets.VersionTaglet;
+import gnu.classpath.tools.taglets.SinceTaglet;
+import gnu.classpath.tools.taglets.DeprecatedTaglet;
+import gnu.classpath.tools.taglets.GenericTaglet;
+import gnu.classpath.tools.doclets.StandardTaglet;
+
+import gnu.classpath.tools.java2xhtml.Java2xhtml;
+
+import gnu.classpath.tools.IOToolkit;
+import gnu.classpath.tools.FileSystemClassLoader;
+
+/**
+ * A Doclet which retrieves all information presented by the Doclet
+ * API, dumping it to stdout in XML format.
+ *
+ * @author Julian Scheid
+ */
+public class Driver {
+
+ public static final String XMLDOCLET_VERSION = "0.6.1";
+
+ /**
+ * Used for redirecting error messages to <code>/dev/null</code>.
+ */
+ private static class NullErrorReporter implements DocErrorReporter {
+ public void printError(String ignore) {}
+ public void printWarning(String ignore) {}
+ public void printNotice(String ignore) {}
+ }
+
+ /*
+ * Taglet context constants.
+ */
+ private static final int CONTEXT_CONSTRUCTOR = 1;
+ private static final int CONTEXT_FIELD = 2;
+ private static final int CONTEXT_METHOD = 3;
+ private static final int CONTEXT_OVERVIEW = 4;
+ private static final int CONTEXT_PACKAGE = 5;
+ private static final int CONTEXT_TYPE = 6;
+
+ /**
+ * All XML output will go to this stream.
+ */
+ private PrintWriter out;
+
+ /**
+ * How many spaces to indent each XML node level,
+ * i.e. Tab size for output.
+ */
+ private static int indentStep = 1;
+
+ /**
+ * Won't output superfluous spaces if set to true.
+ * If set to false, output will be more legible.
+ */
+ private boolean compress = false;
+
+ /**
+ * Won't output warning messages while fixing
+ * HTML code if set to true.
+ */
+ private boolean noHTMLWarn = false;
+
+ /**
+ * Won't output warning messages when encountering tags
+ * that look like an email address if set to true.
+ */
+ private boolean noEmailWarn = false;
+
+ /**
+ * Will fix HTML if necessary so that each comment
+ * contains valid XML code if set to true. If set
+ * to false, HTML code will not be modified and
+ * instead encapsulated in a CDATA section.
+ */
+ private boolean fixHTML = true;
+
+ /**
+ * User-specified name of the directory where the final version of
+ * the generated files will be written to.
+ *
+ * If no XSLT sheet is given, the XML output will go directly into
+ * this directory. Otherwise, XML output will go to a temporary
+ * directory and XSLT output will go to this directory.
+ */
+ private File targetDirectory = null;
+
+ /**
+ * Directory where XML output will be written to. If no XSLT
+ * sheet was given, this is the target directory specified
+ * by the user. Otherwise, this is a temporary directory.
+ */
+ private File xmlTargetDirectory;
+
+ /**
+ * Contains a number of TargetContexts which describe which XSLT
+ * sheet to apply to the output of this doclet, to what directory
+ * the XSLT output is written, and which postprocess driver to use
+ * to process XSLT output.
+ */
+ private List targets = new ArrayList();
+
+ /**
+ * XML text to include at the end of every generated page. Read
+ * from the file specified on the command line using -bottomnote.
+ * If present, this will be written to the main output file
+ * (index.xml) in node /gjdoc:rootDoc/gjdoc:bottomnote.
+ */
+ private String bottomNote;
+
+ /**
+ * Brief description of the package set. Can be specified on the
+ * command line using -title. This will be written to the main
+ * output file (index.xml) in node
+ * /gjdoc:rootDoc/gjdoc:title. The HTML generating XSLT sheet
+ * uses this for example in window titles.
+ */
+ private String title;
+
+ /**
+ * Path to the directory where temporary files should be stored.
+ * Defaults to system tempdir, but can be overridden by user
+ * with -workpath.
+ */
+ private String workingPath = System.getProperty("java.io.tmpdir");
+
+ /**
+ * Temporary directory created by this doclet where all
+ * temporary files will be stored in. If no temporary
+ * files are needed (i.e. no XSLT postprocessing stage
+ * specified by user), this is <code>null</code>.
+ */
+ private File workingDirectory;
+
+ /**
+ * Whether to deep-copy the doc-files subdirectory.
+ */
+ private boolean docFilesSubdirsEnabled = false;
+
+ /**
+ * Which direct subdirectories of the doc-files directories to exclude.
+ * Set of String.
+ */
+ private Set excludeDocFilesSubDirs = new HashSet();
+
+ /**
+ * Stores the Doclet API RootDoc we are operating on.
+ */
+ private RootDoc rootDoc;
+
+ /**
+ * XML namespace prefix used for all tags, except for HTML
+ * tags copied from Javadoc comments. Excluding colon.
+ */
+ public static final String tagPrefix = "gjdoc";
+
+ /**
+ * Classpath for loading Taglet classes.
+ */
+ private String tagletPath = null;
+
+ /**
+ * The current class that is being processed.
+ * Set in outputClassDoc().
+ */
+ private ClassDoc currentClass;
+
+ /**
+ * The current member that is being processed.
+ * Set in outputMemberDoc().
+ */
+ private MemberDoc currentMember;
+
+ /**
+ * The current constructor/method that is being processed.
+ * Set in outputExecutableMemberDoc().
+ */
+ private ExecutableMemberDoc currentExecMember;
+
+ /**
+ * Mapping from tag type to Taglet for user Taglets specified on
+ * the command line.
+ */
+ private Map tagletMap = new LinkedHashMap();
+
+ /**
+ * Keeps track of the tags mentioned by the user during option
+ * processiong so that an error can be emitted if a tag is
+ * mentioned more than once.
+ */
+ private List mentionedTags = new LinkedList();
+
+ /**
+ * Stores options to be passed to the DocTranslet.
+ */
+ private DocTransletOptions docTransletOptions = new DocTransletOptions();
+
+ /**
+ * Stores the package groups specified in the user
+ * options. Contains objects of type PackageGroup.
+ */
+ private List packageGroups = new LinkedList();
+
+ private HtmlRepairer htmlRepairer;
+
+ public static boolean start(TemporaryStore _rootDocWrapper) {
+ return new Driver().instanceStart((RootDoc)_rootDocWrapper.getAndClear());
+ }
+
+ /**
+ * Official Doclet entry point.
+ */
+ public static boolean start(RootDoc _rootDoc) {
+
+ // Create a new XmlDoclet instance and delegate control.
+ TemporaryStore tstore = new TemporaryStore(_rootDoc);
+ _rootDoc = null;
+ return new Driver().instanceStart((RootDoc)tstore.getAndClear());
+ }
+
+ /**
+ * Output an XML tag describing a com.sun.javadoc.Type object.
+ * Assumes that the tag does not have subtags.
+ *
+ * @param level Level of indentation. Will be multiplied by
+ * <code>indentStep</code> to yield actual amount
+ * of whitespace inserted at start of line.
+ * @param tag Identifier for the XML tag being output.
+ * @param type The Javadoc Type to be output.
+ */
+ protected void outputType(int level, String tag, Type type) {
+ outputType(level, tag, type, true);
+ }
+
+ protected void outputType(int level, String tag, Type type, boolean atomic) {
+
+ boolean isIncluded = false;
+ ClassDoc typeAsClassDoc = type.asClassDoc();
+ String packageName = null;
+ if (null != typeAsClassDoc) {
+ isIncluded = typeAsClassDoc.isIncluded();
+ packageName = typeAsClassDoc.containingPackage().name();
+ }
+ println(level, "<"+tagPrefix+":"+tag + " typename=\""+type.typeName()+"\""+
+ " qualifiedtypename=\""+type.qualifiedTypeName()+"\""
+ +(type.dimension().length()==0?"":" dimension=\""+type.dimension()+"\"")
+ +(isIncluded?" isIncluded=\"true\"" : "")
+ +((null != packageName)?" package=\"" + packageName + "\"" : "")
+ +(atomic?"/":"")+">");
+ }
+
+ protected void outputExecutableMemberDocBody(int level, ExecutableMemberDoc memberDoc) {
+
+ currentExecMember = memberDoc;
+
+ outputMemberDocBody(level, memberDoc);
+
+ Parameter[] parameters = memberDoc.parameters();
+ for (int i=0, ilim=parameters.length; i<ilim; ++i) {
+ Parameter parameter = parameters[i];
+ outputType(level, "parameter name=\""+parameter.name()+"\"", parameter.type());
+ }
+
+ ClassDoc[] exceptions = memberDoc.thrownExceptions();
+ for (int i=0, ilim=exceptions.length; i<ilim; ++i) {
+ ClassDoc exception = exceptions[i];
+ outputType(level, "thrownException", exception);
+ }
+
+ printAtomTag(level, "signature full=\""+memberDoc.signature()+"\" flat=\""+memberDoc.flatSignature()+"\"");
+
+ if (memberDoc.isNative()) {
+ printAtomTag(level, "isNative");
+ }
+
+ if (memberDoc.isSynchronized()) {
+ printAtomTag(level, "isSynchronized");
+ }
+ }
+
+ protected void outputMethodDoc(int level, MethodDoc methodDoc) {
+ println();
+ printOpenTag(level, "methoddoc name=\""+methodDoc.name()+"\"");
+ outputExecutableMemberDocBody(level+1, methodDoc);
+ outputType(level+1, "returns", methodDoc.returnType());
+ printCloseTag(level, "methoddoc");
+ }
+
+ protected void outputMemberDocBody(int level, MemberDoc memberDoc) {
+ currentMember = memberDoc;
+ outputProgramElementDocBody(level, memberDoc);
+ }
+
+ protected void outputFieldDocBody(int level, FieldDoc fieldDoc) {
+ outputType(level, "type", fieldDoc.type());
+ if (fieldDoc.isTransient()) {
+ printAtomTag(level, "isTransient");
+ }
+ if (fieldDoc.isVolatile()) {
+ printAtomTag(level, "isVolatile");
+ }
+ }
+
+ private void outputFieldDoc(int level, FieldDoc fieldDoc) {
+ println();
+ printOpenTag(level, "fielddoc name=\""+fieldDoc.name()+"\"");
+ outputMemberDocBody(level+1, fieldDoc);
+ outputFieldDocBody(level+1, fieldDoc);
+ printCloseTag(level, "fielddoc");
+ }
+
+ protected void outputConstructorDoc(int level, ConstructorDoc constructorDoc) {
+ println();
+ printOpenTag(level, "constructordoc name=\""+constructorDoc.name()+"\"");
+ outputExecutableMemberDocBody(level+1, constructorDoc);
+ printCloseTag(level, "constructordoc");
+ }
+
+ protected void outputSuperInterfacesRec(int level, ClassDoc classDoc) {
+ if (null!=classDoc) {
+ ClassDoc[] interfaces = classDoc.interfaces();
+ if (null != interfaces) {
+ for (int i=0, ilim=interfaces.length; i<ilim; ++i) {
+ outputType(level, "superimplements", interfaces[i]);
+ }
+ }
+ outputSuperInterfacesRec(level, classDoc.superclass());
+ }
+ }
+
+ protected void outputClassDocSummary(ClassDoc classDoc) {
+ println();
+ printOpenTag(1, "classdoc name=\""+classDoc.name()+"\" qualifiedtypename=\""+classDoc.qualifiedName()+"\" isIncluded=\"true\"");
+ if (null!=classDoc.superclass()) {
+ outputType(2, "superclass", classDoc.superclass());
+ }
+
+ ClassDoc[] interfaces = classDoc.interfaces();
+ for (int i=0, ilim=interfaces.length; i<ilim; ++i) {
+ outputType(2, "implements", interfaces[i]);
+ }
+ outputSuperInterfacesRec(2, classDoc.superclass());
+
+ printAtomTag(2, "containingPackage name=\""+classDoc.containingPackage().name()+"\"");
+ if (classDoc.isError()) {
+ printAtomTag(2, "isError");
+ }
+ if (classDoc.isException()) {
+ printAtomTag(2, "isException");
+ }
+ if (classDoc.isInterface()) {
+ printAtomTag(2, "isInterface");
+ }
+ if (classDoc.isOrdinaryClass()) {
+ printAtomTag(2, "isOrdinaryClass");
+ }
+
+ printCloseTag(1, "classdoc");
+ }
+
+ protected void outputPackageDoc(PackageDoc packageDoc) {
+ println();
+ printOpenTag(1, "packagedoc name=\""+packageDoc.name()+"\"");
+ if (packageDoc.firstSentenceTags().length > 0) {
+ printOpenTag(2, "firstSentenceTags", false);
+ outputTags(3, packageDoc.firstSentenceTags(), true, CONTEXT_PACKAGE);
+ printCloseTag(0, "firstSentenceTags");
+ printOpenTag(2, "inlineTags", false);
+ outputTags(3, packageDoc.inlineTags(), true, CONTEXT_PACKAGE);
+ printCloseTag(0, "inlineTags");
+ }
+
+ if (packageDoc.tags().length > 0) {
+ printOpenTag(2, "tags");
+ outputTags(3, packageDoc.tags(), true, CONTEXT_PACKAGE);
+ printCloseTag(2, "tags");
+ }
+
+ if (packageDoc.seeTags().length > 0) {
+ printOpenTag(2, "seeTags");
+ outputTags(3, packageDoc.seeTags(), true, CONTEXT_PACKAGE);
+ printCloseTag(2, "seeTags");
+ }
+
+ ClassDoc[] allClasses = (ClassDoc[]) packageDoc.allClasses().clone();
+ Arrays.sort(allClasses);
+
+ if (false) {
+ for (int i = 0, ilim = allClasses.length; i < ilim; ++ i) {
+ printAtomTag(2, "containsClass qualifiedtypename=\""+allClasses[i].qualifiedTypeName()+"\"");
+ }
+ }
+
+ printCloseTag(1, "packagedoc");
+ }
+
+ protected void outputClassDoc(ClassDoc classDoc) throws IOException {
+
+ currentClass = classDoc;
+
+ println();
+ printOpenTag(1, "classdoc xmlns=\"http://www.w3.org/TR/REC-html40\" xmlns:"+tagPrefix+"=\"http://www.gnu.org/software/cp-tools/gjdocxml\" name=\""+classDoc.name()+"\" qualifiedtypename=\""+classDoc.qualifiedName()+"\"");
+
+ ClassDoc[] interfaces = classDoc.interfaces();
+ for (int i=0, ilim=interfaces.length; i<ilim; ++i) {
+ outputType(2, "implements", interfaces[i]);
+ }
+ outputSuperInterfacesRec(2, classDoc.superclass());
+
+ outputProgramElementDocBody(2, classDoc);
+ if (classDoc.isAbstract())
+ printAtomTag(2, "isAbstract");
+ if (classDoc.isSerializable())
+ printAtomTag(2, "isSerializable");
+ if (classDoc.isExternalizable())
+ printAtomTag(2, "isExternalizable");
+ if (classDoc.definesSerializableFields()) {
+ printAtomTag(2, "definesSerializableFields");
+ }
+
+ ConstructorDoc[] constructors = classDoc.constructors();
+ for (int i=0, ilim=constructors.length; i<ilim; ++i) {
+ outputConstructorDoc(2, constructors[i]);
+ }
+
+ MethodDoc[] methods = classDoc.methods();
+ for (int i=0, ilim=methods.length; i<ilim; ++i) {
+ outputMethodDoc(2, methods[i]);
+ }
+
+ FieldDoc[] fields = classDoc.fields();
+ for (int i=0, ilim=fields.length; i<ilim; ++i) {
+ outputFieldDoc(2, fields[i]);
+ }
+
+ if (classDoc.serializableFields().length > 0) {
+ printOpenTag(2, "serializableFields");
+
+ FieldDoc[] sfields = classDoc.serializableFields();
+ for (int i=0, ilim=sfields.length; i<ilim; ++i) {
+ outputFieldDoc(2, sfields[i]);
+ }
+ printCloseTag(2, "serializableFields");
+ }
+
+ Java2xhtml java2xhtml = new Java2xhtml();
+ Properties properties = new Properties();
+ properties.setProperty("isCodeSnippet", "true");
+ properties.setProperty("hasLineNumbers", "true");
+ java2xhtml.setProperties(properties);
+
+ if (null == classDoc.containingClass() && docTransletOptions.linksource) {
+ printOpenTag(2, "source");
+ StringWriter sourceBuffer = new StringWriter();
+ File sourceFile = new File(((GjdocPackageDoc)classDoc.containingPackage()).packageDirectory(),
+ classDoc.name() + ".java");
+ FileReader sourceReader = new FileReader(sourceFile);
+ IOToolkit.copyStream(sourceReader, sourceBuffer);
+ print(java2xhtml.makeHTML(sourceBuffer.getBuffer(), sourceFile.getName()));
+ printCloseTag(2, "source");
+ }
+
+ ClassDoc superclassDoc = classDoc.superclass();
+ while (superclassDoc != null) {
+ outputType(2, "superclass", superclassDoc, false);
+
+ // FIXME: remove the following after adjusting the XSLT sheets:
+ printAtomTag(3, "containingPackage name=\"" + superclassDoc.containingPackage().name() + "\"");
+
+ MethodDoc[] superMethods = superclassDoc.methods();
+ if (null != superMethods) {
+ for (int i=0, ilim=superMethods.length; i<ilim; ++i) {
+ printAtomTag(3, "methoddoc name=\"" + superMethods[i].name() + "\" signature=\"" + superMethods[i].signature() + "\"");
+ }
+ }
+
+ FieldDoc[] superFields = superclassDoc.fields();
+ if (null != superFields) {
+ for (int i=0, ilim=superFields.length; i<ilim; ++i) {
+ printAtomTag(3, "fielddoc name=\"" + superFields[i].name() + "\"");
+ }
+ }
+ printCloseTag(2, "superclass");
+
+ superclassDoc = superclassDoc.superclass();
+ }
+
+ outputUsage(classDoc, 2);
+
+ printCloseTag(1, "classdoc");
+
+ currentClass = null;
+ currentMember = null;
+ currentExecMember = null;
+ }
+
+ protected int outputHeritageOpen(int level, ClassDoc classDoc) {
+
+ ClassDoc superClassDoc = classDoc.superclass();
+ if (null != superClassDoc) {
+ level = outputHeritageOpen(level, superClassDoc);
+ ++ level;
+ }
+ outputType(level, "heritage", classDoc, false);
+ return level;
+ }
+
+ protected void outputHeritageClose(int level, ClassDoc classDoc) {
+
+ ClassDoc superClassDoc = classDoc.superclass();
+ if (null != superClassDoc) {
+ outputHeritageClose(level + 1, superClassDoc);
+ }
+ printCloseTag(level, "heritage");
+ }
+
+ protected void outputDocBody(int level, Doc doc) {
+
+ int context = CONTEXT_TYPE;
+
+ if (doc.isClass()) {
+ printAtomTag(level, "isClass");
+
+ ClassDoc classDoc = (ClassDoc)doc;
+ ClassDoc[] classes = rootDoc.classes();
+ for (int i=0, ilim=classes.length; i<ilim; ++i) {
+ if (classes[i].superclass() == classDoc) {
+ outputType(level, "extended-by", classes[i]);
+ }
+ }
+
+ outputHeritageOpen(level, classDoc);
+ outputHeritageClose(level, classDoc);
+ }
+ if (doc.isConstructor()) {
+ printAtomTag(level, "isConstructor");
+ context = CONTEXT_CONSTRUCTOR;
+ }
+ if (doc.isError()) {
+ printAtomTag(level, "isError");
+ }
+ if (doc.isException()) {
+ printAtomTag(level, "isException");
+ }
+ if (doc.isField()) {
+ printAtomTag(level, "isField");
+ context = CONTEXT_FIELD;
+ }
+ if (doc.isIncluded()) {
+ printAtomTag(level, "isIncluded");
+ }
+ if (doc.isInterface()) {
+ printAtomTag(level, "isInterface");
+
+ ClassDoc classDoc = (ClassDoc)doc;
+ ClassDoc[] classes = rootDoc.classes();
+ for (int i=0, ilim=classes.length; i<ilim; ++i) {
+ ClassDoc[] implementedInterfaces = classes[i].interfaces();
+ for (int j=0; j<implementedInterfaces.length; ++j) {
+ if (implementedInterfaces[j] == classDoc) {
+ if (classDoc.isInterface()) {
+ outputType(level, "subinterface", classes[i]);
+ }
+ else {
+ outputType(level, "implemented-by", classes[i]);
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (doc.isMethod()) {
+ printAtomTag(level, "isMethod");
+ context = CONTEXT_METHOD;
+ }
+ if (doc.isOrdinaryClass()) {
+ printAtomTag(level, "isOrdinaryClass");
+ }
+
+ if (doc.inlineTags().length > 0) {
+ printOpenTag(level, "inlineTags", false);
+ outputTags(level+1, doc.inlineTags(), true, context);
+ printCloseTag(0, "inlineTags");
+ }
+
+ if (doc.firstSentenceTags().length > 0) {
+ printOpenTag(level, "firstSentenceTags", false);
+ outputTags(level+1, doc.firstSentenceTags(), true, context);
+ printCloseTag(0, "firstSentenceTags");
+ }
+
+ if (doc.tags().length > 0) {
+ printOpenTag(level, "tags");
+ outputTaglets(level+1, doc.tags(), true, context);
+ printCloseTag(level, "tags");
+ }
+
+ if (doc.seeTags().length > 0) {
+ printOpenTag(level, "seeTags");
+ outputTags(level+1, doc.seeTags(), true, context);
+ printCloseTag(level, "seeTags");
+ }
+
+ SourcePosition position = doc.position();
+ if (null != position) {
+ printAtomTag(level, "position file=\"" + position.file().getAbsolutePath() + "\" line=\"" + position.line() + "\" column=\"" + position.column() + "\"");
+ }
+ }
+
+ protected void outputProgramElementDocBody(int level, ProgramElementDoc programElementDoc) {
+ outputDocBody(level, programElementDoc);
+ printAtomTag(level, "containingPackage name=\""+programElementDoc.containingPackage().name()+"\"");
+ if (null!=programElementDoc.containingClass()) {
+ outputType(level, "containingClass", programElementDoc.containingClass());
+ }
+ String access;
+ if (programElementDoc.isPublic())
+ access="public";
+ else if (programElementDoc.isProtected())
+ access="protected";
+ else if (programElementDoc.isPrivate())
+ access="private";
+ else if (programElementDoc.isPackagePrivate())
+ access="package";
+ else
+ throw new RuntimeException("Huh? "+programElementDoc+" is neither public, protected, private nor package protected.");
+ printAtomTag(level, "access scope=\""+access+"\"");
+ if (programElementDoc.isFinal())
+ printAtomTag(level, "isFinal");
+ if (programElementDoc.isStatic())
+ printAtomTag(level, "isStatic");
+ }
+
+ protected void outputTags(int level, Tag[] tags, boolean descend, int context) {
+
+ for (int i=0; i<tags.length; ++i) {
+ outputTag(tags[i], level, descend, context, i == tags.length-1);
+ }
+ }
+
+ protected void outputTag(Tag tag, int level, boolean descend, int context, boolean lastTag) {
+
+ if (!"Text".equals(tag.name())) {
+ printOpenTag(0 /* don't introduce additional whitespace */,
+ "tag kind=\""+tag.kind()+"\" name=\""+tag.name()+"\"", false);
+ }
+ if (tag instanceof ThrowsTag) {
+ ThrowsTag throwsTag = (ThrowsTag)tag;
+ if (null!=throwsTag.exception()) {
+ outputType(level+1, "exception", throwsTag.exception());
+ }
+ else {
+ StringBuffer sb = new StringBuffer("Exception ");
+ sb.append(throwsTag.exceptionName());
+ sb.append(" not found in ");
+ if (currentExecMember instanceof MethodDoc) {
+ MethodDoc m = (MethodDoc)currentExecMember;
+ sb.append(m.returnType().typeName());
+ sb.append(m.returnType().dimension());
+ sb.append(' ');
+ }
+ sb.append(currentClass.qualifiedName());
+ sb.append('.');
+ sb.append(currentExecMember.name());
+ sb.append('(');
+ Parameter[] params = currentExecMember.parameters();
+ for (int j=0; j < params.length; j++) {
+ sb.append(params[j].type().typeName());
+ sb.append(params[j].type().dimension());
+ sb.append(' ');
+ sb.append(params[j].name());
+ if (j != params.length-1)
+ sb.append(", ");
+ }
+ sb.append(')');
+ printWarning(sb.toString());
+
+ printAtomTag(level+1, "exception typename=\""+throwsTag.exceptionName()+"\"");
+ }
+ }
+ else if (tag instanceof ParamTag) {
+ ParamTag paramTag = (ParamTag)tag;
+ printAtomTag(level+1, "parameter name=\""+paramTag.parameterName()+"\"");
+ }
+
+ if (null != tag.text()) {
+ //printOpenTag(level+1, "text", false);
+ if (fixHTML) {
+ print(htmlRepairer.getWellformedHTML(tag.text()));
+ }
+ else {
+ print("<![CDATA["+cdata(tag.text())+"]]>");
+ }
+ //printCloseTag(0 /* don't introduce additional whitespace */, "text");
+ }
+ else {
+ printWarning("Tag got null text: "+tag);
+ }
+
+ if ((descend && ("@throws".equals(tag.name()) || "@param".equals(tag.name()))) || "@deprecated".equals(tag.name())) {
+ if (tag.firstSentenceTags().length>0) {
+ printOpenTag(level+1, "firstSentenceTags", false);
+ outputTags(level+2, tag.firstSentenceTags(), false, context);
+ printCloseTag(0, "firstSentenceTags");
+ }
+
+ if (tag.inlineTags().length>0) {
+ printOpenTag(level+1, "inlineTags", false);
+ outputTags(level+2, tag.firstSentenceTags(), false, context);
+ printCloseTag(0, "inlineTags");
+ }
+ }
+
+ if (fixHTML && lastTag) {
+ String terminateText = htmlRepairer.terminateText();
+ if (null != terminateText && terminateText.length() > 0) {
+ print(terminateText);
+ }
+ }
+
+ if (!"Text".equals(tag.name())) {
+
+ Taglet inlineTaglet = (Taglet)tagletMap.get(tag.name().substring(1));
+ if (null != inlineTaglet && inlineTaglet.isInlineTag()) {
+ printOpenTag(0, "inlineTagletText", false);
+ print(inlineTaglet.toString(tag));
+ printCloseTag(0, "inlineTagletText");
+ }
+
+ printCloseTag(0, "tag", false);
+ }
+ }
+
+ void outputTaglets(int level, Tag[] tags, boolean descend, int context)
+ {
+ for (Iterator it = tagletMap.keySet().iterator(); it.hasNext(); ) {
+ String tagName = (String)it.next();
+ Object o = tagletMap.get(tagName);
+ Taglet taglet = (Taglet)o;
+
+ if (!taglet.isInlineTag()
+ && ((context != CONTEXT_CONSTRUCTOR || taglet.inConstructor())
+ || (context != CONTEXT_FIELD || taglet.inField())
+ || (context != CONTEXT_METHOD || taglet.inMethod())
+ || (context != CONTEXT_OVERVIEW || taglet.inOverview())
+ || (context != CONTEXT_PACKAGE || taglet.inPackage())
+ || (context != CONTEXT_TYPE || taglet.inType()))) {
+
+ List tagsOfThisType = new ArrayList();
+ for (int i=0, ilim=tags.length; i<ilim; ++i) {
+ if (tags[i].name().substring(1).equals(tagName)) {
+ tagsOfThisType.add(tags[i]);
+ }
+ }
+
+ if (!tagsOfThisType.isEmpty()) {
+ Tag[] tagletTags = (Tag[])tagsOfThisType.toArray(new Tag[tagsOfThisType.size()]);
+ if (taglet instanceof StandardTaglet) {
+ Iterator tagIterator = tagsOfThisType.iterator();
+ while (tagIterator.hasNext()) {
+ Tag tag = (Tag)tagIterator.next();
+ outputTag(tag, level, descend, context, !tagIterator.hasNext());
+ }
+ }
+ else {
+ String tagletString = taglet.toString(tagletTags);
+ if (null != tagletString) {
+ printOpenTag(0, "tag name=\"" + tagName + "\" taglet-generated=\"true\"");
+ if (fixHTML) {
+ print(htmlRepairer.getWellformedHTML(tagletString));
+ print(htmlRepairer.terminateText());
+ }
+ else {
+ print("<![CDATA["+cdata(tagletString)+"]]>");
+ }
+ printCloseTag(0, "tag", false);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Inofficial entry point. We got an instance here.
+ */
+ protected boolean instanceStart(RootDoc _rootDoc) {
+
+ this.rootDoc = _rootDoc;
+ _rootDoc = null;
+
+ boolean xmlOnly = true;
+
+ // Set the default Taglet order
+
+ registerTaglet(new VersionTaglet());
+ registerTaglet(new AuthorTaglet());
+ //registerTaglet(new SinceTaglet());
+ registerTaglet(new StandardTaglet("deprecated"));
+ registerTaglet(new StandardTaglet("see"));
+ registerTaglet(new StandardTaglet("param"));
+
+ // Set the built-in Taglet filter
+
+ AuthorTaglet.setTagletEnabled(false);
+ VersionTaglet.setTagletEnabled(false);
+ SinceTaglet.setTagletEnabled(true);
+ DeprecatedTaglet.setTagletEnabled(true);
+
+ try {
+ {
+
+ // Process command line options passed through to this doclet
+
+ TargetContext targetContext = null;
+
+ TargetContext htmlTargetContext
+ = new TargetContext(DocTranslet.fromClasspath("/doctranslets/html/gjdoc.xsl"),
+ targetDirectory);
+
+ for (int i=0, ilim=rootDoc.options().length; i<ilim; ++i) {
+
+ String[] option = rootDoc.options()[i];
+ String optionTag = option[0];
+
+ if ("-d".equals(optionTag)) {
+ if (null == targetDirectory) {
+ targetDirectory = new File(option[1]);
+ }
+ if (null != targetContext) {
+ targetContext.setTargetDirectory(targetDirectory);
+ }
+ }
+
+ else if ("-nofixhtml".equals(optionTag)) {
+ fixHTML = false;
+ printError("-nofixhtml currently not supported.");
+ return false;
+ }
+ else if ("-compress".equals(optionTag)) {
+ compress = true;
+ }
+ else if ("-nohtmlwarn".equals(optionTag)) {
+ noHTMLWarn = true;
+ }
+ else if ("-noemailwarn".equals(optionTag)) {
+ noEmailWarn = true;
+ }
+ else if ("-indentstep".equals(optionTag)) {
+ indentStep = Integer.parseInt(option[1]);
+ }
+ else if ("-doctranslet".equals(optionTag)) {
+ targets.add(targetContext = new TargetContext(DocTranslet.fromJarFile(new File(option[1])),
+ targetDirectory));
+ }
+ else if ("-genhtml".equals(optionTag)) {
+ htmlTargetContext.setTargetDirectory(targetDirectory);
+ targets.add(targetContext = htmlTargetContext);
+ xmlOnly = false;
+ }
+ else if ("-geninfo".equals(optionTag)) {
+ targetContext
+ = new TargetContext(DocTranslet.fromClasspath("/doctranslets/info/gengj.xsl"),
+ targetDirectory);
+ targets.add(targetContext);
+ if (!fixHTML) {
+ printNotice("NOTE: -geninfo implies -fixhtml.");
+ fixHTML = true;
+ }
+ xmlOnly = false;
+ }
+ else if ("-gendocbook".equals(optionTag)) {
+ targetContext = new TargetContext(DocTranslet.fromClasspath("/doctranslets/docbook/gengj.xsl"),
+ targetDirectory);
+ targets.add(targetContext);
+ if (!fixHTML) {
+ printNotice("NOTE: -gendocbook implies -fixhtml.");
+ fixHTML = true;
+ }
+ }
+ else if ("-genpdf".equals(optionTag)) {
+ targetContext
+ = new TargetContext(DocTranslet.fromClasspath("/doctranslets/docbook/gengj.xsl"),
+ targetDirectory);
+ /** "gnu.classpath.tools.doclets.xmldoclet.DocBookPostprocessor") **/
+ targets.add(targetContext);
+ if (!fixHTML) {
+ printNotice("NOTE: -genpdf implies -fixhtml.");
+ fixHTML = true;
+ }
+ }
+ else if ("-xmlonly".equals(optionTag)) {
+ xmlOnly = true;
+ }
+ else if ("-bottomnote".equals(optionTag)) {
+
+ FileReader reader = new FileReader(option[1]);
+ StringWriter writer = new StringWriter();
+ char[] buf = new char[256];
+ int nread;
+ while ((nread = reader.read(buf)) >= 0) {
+ writer.write(buf, 0, nread);
+ }
+ writer.flush();
+ bottomNote = writer.toString();
+ writer.close();
+ reader.close();
+ }
+ else if ("-title".equals(optionTag)) {
+
+ title = option[1];
+ }
+ else if ("-workpath".equals(optionTag)) {
+
+ workingPath = option[1];
+ }
+ else if ("-tagletpath".equals(optionTag)) {
+
+ if (null == tagletPath) {
+ tagletPath = option[1];
+ }
+ else {
+ tagletPath = tagletPath + File.pathSeparator + option[1];
+ }
+ }
+ else if ("-taglet".equals(optionTag)) {
+
+ boolean tagletLoaded = false;
+
+ String useTagletPath = this.tagletPath;
+ if (null == useTagletPath) {
+ useTagletPath = System.getProperty("java.class.path");
+ }
+
+ try {
+ Class tagletClass;
+ try {
+ tagletClass
+ = new FileSystemClassLoader(useTagletPath).loadClass(option[1]);
+ }
+ catch (ClassNotFoundException e) {
+ // If not found on specified tagletpath, try default classloader
+ tagletClass
+ = Class.forName(option[1]);
+ }
+ Method registerTagletMethod
+ = tagletClass.getDeclaredMethod("register", new Class[] { java.util.Map.class });
+
+ if (!registerTagletMethod.getReturnType().equals(Void.TYPE)) {
+ printError("Taglet class '" + option[1] + "' found, but register method doesn't return void.");
+ }
+ else if (registerTagletMethod.getExceptionTypes().length > 0) {
+ printError("Taglet class '" + option[1] + "' found, but register method contains throws clause.");
+ }
+ else if ((registerTagletMethod.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC | Modifier.ABSTRACT)) != (Modifier.STATIC | Modifier.PUBLIC)) {
+ printError("Taglet class '" + option[1] + "' found, but register method isn't public static, or is abstract..");
+ }
+ else {
+ Map tempMap = new HashMap();
+ registerTagletMethod.invoke(null, new Object[] { tempMap });
+ tagletLoaded = true;
+ String name = (String)tempMap.keySet().iterator().next();
+ Taglet taglet = (Taglet)tempMap.get(name);
+ tagletMap.put(name, taglet);
+ mentionedTags.add(taglet);
+ }
+ }
+ catch (NoSuchMethodException e) {
+ printError("Taglet class '" + option[1] + "' found, but doesn't contain the register method.");
+ }
+ catch (SecurityException e) {
+ printError("Taglet class '" + option[1] + "' cannot be loaded: " + e.getMessage());
+ }
+ catch (InvocationTargetException e) {
+ printError("Taglet class '" + option[1] + "' found, but register method throws exception: " + e.toString());
+ }
+ catch (IllegalAccessException e) {
+ printError("Taglet class '" + option[1] + "' found, but there was a problem when accessing the register method: " + e.toString());
+ }
+ catch (IllegalArgumentException e) {
+ printError("Taglet class '" + option[1] + "' found, but there was a problem when accessing the register method: " + e.toString());
+ }
+ catch (ClassNotFoundException e) {
+ printError("Taglet class '" + option[1] + "' cannot be found.");
+ }
+ if (!tagletLoaded) {
+ return false;
+ }
+ }
+ else if ("-author".equals(optionTag)) {
+ AuthorTaglet.setTagletEnabled(true);
+ }
+ else if ("-version".equals(optionTag)) {
+ VersionTaglet.setTagletEnabled(true);
+ }
+ else if ("-nosince".equals(optionTag)) {
+ SinceTaglet.setTagletEnabled(false);
+ }
+ else if ("-nodeprecated".equals(optionTag)) {
+ DeprecatedTaglet.setTagletEnabled(false);
+ }
+ else if ("-authormail".equals(optionTag)) {
+
+ if ("no-replace".equalsIgnoreCase(option[1])) {
+ AuthorTaglet.setEmailReplacementType(AuthorTaglet.EmailReplacement.NO_REPLACEMENT);
+ }
+ else if ("mailto-name".equalsIgnoreCase(option[1])) {
+ AuthorTaglet.setEmailReplacementType(AuthorTaglet.EmailReplacement.MAILTO_NAME);
+ }
+ else if ("name-mailto-address".equalsIgnoreCase(option[1])) {
+ AuthorTaglet.setEmailReplacementType(AuthorTaglet.EmailReplacement.NAME_MAILTO_ADDRESS);
+ }
+ else if ("name-mangled-address".equalsIgnoreCase(option[1])) {
+ AuthorTaglet.setEmailReplacementType(AuthorTaglet.EmailReplacement.NAME_MANGLED_ADDRESS);
+ }
+ else {
+ printError("Invalid value for option '-authortag-email'. Allowed values are:"
+ + " no-replace, mailto-name, name-mailto-address, name-mangled-address.");
+ return false;
+ }
+ }
+ else if ("-mailmangledot".equals(optionTag)) {
+ AuthorTaglet.setDotReplacement(option[1]);
+ }
+ else if ("-mailmangleat".equals(optionTag)) {
+ AuthorTaglet.setAtReplacement(option[1]);
+ }
+ else if ("-docfilessubdirs".equals(optionTag)) {
+ docFilesSubdirsEnabled = true;
+ }
+ else if ("-excludedocfilessubdir".equals(optionTag)) {
+ StringTokenizer st = new StringTokenizer(option[1]);
+ while (st.hasMoreTokens()) {
+ excludeDocFilesSubDirs.add(st.nextToken());
+ }
+ }
+ else if ("-nonavbar".equals(optionTag)) {
+ docTransletOptions.nonavbar = true;
+ }
+ else if ("-noindex".equals(optionTag)) {
+ docTransletOptions.noindex = true;
+ }
+ else if ("-notree".equals(optionTag)) {
+ docTransletOptions.notree = true;
+ }
+ else if ("-nocomment".equals(optionTag)) {
+ docTransletOptions.nocomment = true;
+ }
+ else if ("-nohelp".equals(optionTag)) {
+ docTransletOptions.nohelp = true;
+ }
+ else if ("-splitindex".equals(optionTag)) {
+ docTransletOptions.splitindex = true;
+ }
+ else if ("-linksource".equals(optionTag)) {
+ docTransletOptions.linksource = true;
+ }
+ else if ("-windowtitle".equals(optionTag)) {
+ docTransletOptions.windowtitle = option[1];
+ }
+ else if ("-helpfile".equals(optionTag)) {
+ docTransletOptions.helpfile = new File(option[1]).toURL().toString();
+ }
+ else if ("-stylesheetfile".equals(optionTag)) {
+ docTransletOptions.stylesheetfile = new File(option[1]).toURL().toString();
+ }
+ else if ("-header".equals(optionTag)) {
+ docTransletOptions.header = option[1];
+ }
+ else if ("-footer".equals(optionTag)) {
+ docTransletOptions.footer = option[1];
+ }
+ else if ("-bottom".equals(optionTag)) {
+ docTransletOptions.bottom = option[1];
+ }
+ else if ("-doctitle".equals(optionTag)) {
+ docTransletOptions.doctitle = option[1];
+ }
+ else if ("-nodeprecatedlist".equals(optionTag)) {
+ docTransletOptions.nodeprecatedlist = true;
+ }
+ else if ("-uses".equals(optionTag)) {
+ docTransletOptions.uses = true;
+ }
+ else if ("-group".equals(optionTag)) {
+ if (!processGroupOption(option[1], option[2])) {
+ printError("Invalid package wildcard list in -group option \"" + option[1] + "\" " + option[2]);
+ return false;
+ }
+ }
+ else if ("-tag".equals(optionTag)) {
+ String tagSpec = option[1];
+ boolean validTagSpec = false;
+ int ndx1 = tagSpec.indexOf(':');
+ if (ndx1 < 0) {
+ Taglet taglet = (Taglet)tagletMap.get(tagSpec);
+ if (null == taglet) {
+ printError("There is no standard tag '" + tagSpec + "'.");
+ }
+ else {
+ if (mentionedTags.contains(taglet)) {
+ printError("Tag '" + tagSpec + "' has been added or moved before.");
+ }
+ else {
+ mentionedTags.add(taglet);
+
+ // re-append taglet
+ tagletMap.remove(tagSpec);
+ tagletMap.put(tagSpec, taglet);
+ }
+ }
+ }
+ else {
+ int ndx2 = tagSpec.indexOf(':', ndx1 + 1);
+ if (ndx2 > ndx1 && ndx2 < tagSpec.length() - 1) {
+ String tagName = tagSpec.substring(0, ndx1);
+ String tagHead = null;
+ if (tagSpec.charAt(ndx2 + 1) == '\"') {
+ if (tagSpec.charAt(tagSpec.length() - 1) == '\"') {
+ tagHead = tagSpec.substring(ndx2 + 2, tagSpec.length() - 1);
+ validTagSpec = true;
+ }
+ }
+ else {
+ tagHead = tagSpec.substring(ndx2 + 1);
+ validTagSpec = true;
+ }
+
+ boolean tagScopeOverview = false;
+ boolean tagScopePackages = false;
+ boolean tagScopeTypes = false;
+ boolean tagScopeConstructors = false;
+ boolean tagScopeMethods = false;
+ boolean tagScopeFields = false;
+ boolean tagDisabled = false;
+
+ tag_option_loop:
+ for (int n=ndx1+1; n<ndx2; ++n) {
+ switch (tagSpec.charAt(n)) {
+ case 'X':
+ tagDisabled = true;
+ break;
+ case 'a':
+ tagScopeOverview = true;
+ tagScopePackages = true;
+ tagScopeTypes = true;
+ tagScopeConstructors = true;
+ tagScopeMethods = true;
+ tagScopeFields = true;
+ break;
+ case 'o':
+ tagScopeOverview = true;
+ break;
+ case 'p':
+ tagScopePackages = true;
+ break;
+ case 't':
+ tagScopeTypes = true;
+ break;
+ case 'c':
+ tagScopeConstructors = true;
+ break;
+ case 'm':
+ tagScopeMethods = true;
+ break;
+ case 'f':
+ tagScopeFields = true;
+ break;
+ default:
+ validTagSpec = false;
+ break tag_option_loop;
+ }
+ }
+
+ if (validTagSpec) {
+ GenericTaglet taglet
+ = new GenericTaglet(tagName,
+ tagHead,
+ tagScopeOverview,
+ tagScopePackages,
+ tagScopeTypes,
+ tagScopeConstructors,
+ tagScopeMethods,
+ tagScopeFields);
+ taglet.setTagletEnabled(!tagDisabled);
+ taglet.register(tagletMap);
+ mentionedTags.add(taglet);
+ }
+ }
+ }
+ if (!validTagSpec) {
+ printError("Value for option -tag must be in format \"<tagname>:Xaoptcmf:<taghead>\".");
+ }
+ }
+ }
+
+ // Use current directory if target directory hasn't been set.
+ if (null == targetDirectory) {
+ targetDirectory = new File(System.getProperty("user.dir"));
+ }
+ if (null != targetContext) {
+ targetContext.setTargetDirectory(targetDirectory);
+ }
+
+ // It is illegal to specify targets AND -xmlonly.
+
+ if (xmlOnly && targets.size() > 0) {
+
+ printError("You can only specify one of -xmlonly and a target format.");
+ return false;
+ }
+
+ // If no target was specified and XML only was not
+ // requested, use HTML as default target.
+
+ if (!xmlOnly && targets.size() == 0) {
+ targets.add(targetContext = htmlTargetContext);
+ }
+
+ // Set the same target directory for all output.
+
+ // FIXME: Allow separate target directories for different
+ // output formats.
+
+ for (Iterator it = targets.iterator(); it.hasNext(); ) {
+ TargetContext t = (TargetContext)it.next();
+ t.setTargetDirectory(targetDirectory);
+ }
+
+ // Create temporary directory if necessary
+
+ if (xmlOnly) {
+
+ xmlTargetDirectory = targetDirectory;
+ }
+ else {
+
+ File workingTopDirectory = new File(workingPath);
+
+ workingDirectory = new File(workingTopDirectory, "gjdoc.tmp."+System.currentTimeMillis());
+
+ if (!workingDirectory.mkdir()) {
+ printError("Cannot create temporary directory at "+System.getProperty("java.io.tmpdir"));
+ return false;
+ }
+
+ File xmlTempDirectory = new File(workingDirectory, "xmloutput");
+
+ if (!xmlTempDirectory.mkdir()) {
+ printError("Cannot create temporary directory for XML output at "+System.getProperty("java.io.tmpdir"));
+ return false;
+ }
+
+ xmlTargetDirectory = xmlTempDirectory;
+ }
+
+ // Create target directory if necessary
+
+ if (!targetDirectory.exists()) {
+ printNotice("Creating destination directory: \""
+ + targetDirectory + "\"");
+ if (!targetDirectory.mkdirs()) {
+ printError("Failed to create destination directory \""
+ + targetDirectory + "\"");
+ return false;
+ }
+ }
+
+ // Check for deprecation
+
+ boolean hasDeprecatedClasses = false;
+ boolean hasDeprecatedInterfaces = false;
+ boolean hasDeprecatedExceptions = false;
+ boolean hasDeprecatedErrors = false;
+ boolean hasDeprecatedMethods = false;
+ boolean hasDeprecatedFields = false;
+
+ {
+ ClassDoc[] classes = rootDoc.classes();
+ for (int i = 0, ilim = classes.length; i < ilim; ++ i) {
+ ClassDoc c = classes[i];
+ Tag[] deprecatedTags = c.tags("deprecated");
+ if (null != deprecatedTags && 0 != deprecatedTags.length) {
+ if (c.isInterface()) {
+ hasDeprecatedInterfaces = true;
+ }
+ else if (c.isException()) {
+ hasDeprecatedExceptions = true;
+ }
+ else if (c.isError()) {
+ hasDeprecatedErrors = true;
+ }
+ else /*if (c.isOrdinaryClass())*/ {
+ hasDeprecatedClasses = true;
+ }
+ }
+
+ MethodDoc[] methods = c.methods();
+ for (int j = 0, jlim = methods.length; j < jlim; ++ j) {
+ MethodDoc m = methods[j];
+ deprecatedTags = m.tags("deprecated");
+ if (null != deprecatedTags && 0 != deprecatedTags.length) {
+ hasDeprecatedMethods = true;
+ }
+ }
+
+ FieldDoc[] fields = c.fields();
+ for (int j = 0, jlim = fields.length; j < jlim; ++ j) {
+ FieldDoc f = fields[j];
+ deprecatedTags = f.tags("deprecated");
+ if (null != deprecatedTags && 0 != deprecatedTags.length) {
+ hasDeprecatedFields = true;
+ }
+ }
+ }
+ }
+
+ htmlRepairer = new HtmlRepairer(rootDoc, noHTMLWarn, noEmailWarn,
+ currentClass, currentMember,
+ false);
+
+ collectUsage();
+
+ // Begin XML generation
+
+ printNotice("Writing XML Index file...");
+
+ // Assign output stream
+
+ setTargetFile("index.xml");
+
+ // Output XML document header
+
+ println(0, "<?xml version=\"1.0\"?>");
+ println("<!DOCTYPE gjdoc SYSTEM \"dtd/gjdoc.dtd\">");
+ println();
+ printOpenTag(0, "rootdoc xmlns=\"http://www.w3.org/TR/REC-html40\" xmlns:gjdoc=\"http://www.gnu.org/software/cp-tools/gjdocxml\"");
+
+ println();
+ println(1, "<!-- Tags from overview page, if available -->");
+
+ if (rootDoc.firstSentenceTags().length > 0) {
+ printOpenTag(2, "firstSentenceTags", false);
+ outputTags(3, rootDoc.firstSentenceTags(), true, CONTEXT_PACKAGE);
+ printCloseTag(0, "firstSentenceTags");
+ }
+
+ if (rootDoc.inlineTags().length > 0) {
+ printOpenTag(2, "inlineTags");
+ outputTags(3, rootDoc.inlineTags(), true, CONTEXT_PACKAGE);
+ printCloseTag(2, "inlineTags");
+ }
+
+ if (null != bottomNote) {
+ printOpenTag(1, "bottomnote");
+ print(bottomNote);
+ printCloseTag(1, "bottomnote");
+ }
+
+ if (null != title) {
+ printOpenTag(1, "title");
+ println(2, title);
+ printCloseTag(1, "title");
+ }
+
+ printOpenTag(1, "created");
+ println(2, DateFormat.getDateInstance(DateFormat.LONG, Locale.US).format(new java.util.Date()));
+ printCloseTag(1, "created");
+
+ if (hasDeprecatedClasses) printAtomTag(1, "hasDeprecatedClasses");
+ if (hasDeprecatedInterfaces) printAtomTag(1, "hasDeprecatedInterfaces");
+ if (hasDeprecatedExceptions) printAtomTag(1, "hasDeprecatedExceptions");
+ if (hasDeprecatedErrors) printAtomTag(1, "hasDeprecatedErrors");
+ if (hasDeprecatedMethods) printAtomTag(1, "hasDeprecatedMethods");
+ if (hasDeprecatedFields) printAtomTag(1, "hasDeprecatedFields");
+
+ // Output summary of all classes specified on command line
+
+ println();
+ println(1, "<!-- Classes specified by user on command line -->");
+ ClassDoc[] specifiedClasses = rootDoc.specifiedClasses();
+ for (int i=0, ilim=specifiedClasses.length; i<ilim; ++i) {
+ ClassDoc sc = specifiedClasses[i];
+ printAtomTag(1, "specifiedclass fqname=\""+sc.qualifiedName()+"\" name=\""+sc.name()+"\"");
+ }
+ specifiedClasses = null;
+
+ // Output summary of all packages specified on command line
+
+ println();
+ println(1, "<!-- Packages specified by user on command line -->");
+ PackageDoc[] specifiedPackages = rootDoc.specifiedPackages();
+ for (int i=0, ilim=specifiedPackages.length; i<ilim; ++i) {
+ PackageDoc sp = specifiedPackages[i];
+ printAtomTag(1, "specifiedpackage name=\""+sp.name()+"\"");
+ }
+ specifiedPackages = null;
+
+ // Output package group information specified on the
+ // command line
+
+ println();
+ println(1, "<!-- Package groups specified by user on command line -->");
+ {
+ Iterator packageGroupIt = packageGroups.iterator();
+ while (packageGroupIt.hasNext()) {
+ PackageGroup packageGroup = (PackageGroup)packageGroupIt.next();
+ SortedSet groupedPackages = packageGroup.getPackages();
+ if (groupedPackages.isEmpty()) {
+ printWarning("Package group named '"
+ + packageGroup.getName() + "' didn't match any packages.");
+ }
+ else {
+ printOpenTag(1, "packagegroup name=\"" + packageGroup.getName() + "\"");
+ Iterator groupedPackageIt = groupedPackages.iterator();
+ while (groupedPackageIt.hasNext()) {
+ PackageDoc groupedPackageDoc = (PackageDoc)groupedPackageIt.next();
+ printAtomTag(2, "package name=\"" + groupedPackageDoc.name() + "\"");
+ }
+ printCloseTag(1, "packagegroup");
+ }
+ }
+ packageGroups = null;
+ }
+
+ // Output information on all packages for which documentation
+ // has been made available via the Doclet API
+
+ println();
+ println(1, "<!-- Documentation for all packages -->");
+ PackageDoc[] packages = rootDoc.specifiedPackages();
+ for (int i=0, ilim=packages.length; i<ilim; ++i) {
+ PackageDoc c = packages[i];
+ outputPackageDoc(c);
+ }
+ packages = null;
+
+ // Output brief summary on all classes for which documentation
+ // has been made available via the Doclet API.
+ //
+ // While this is redundant, it can speed up XSLT
+ // processing by orders of magnitude
+
+ println();
+ println(1, "<!-- Brief summary for all classes -->");
+ ClassDoc[] sumclasses = rootDoc.classes();
+ for (int i=0, ilim=sumclasses.length; i<ilim; ++i) {
+ ClassDoc c = sumclasses[i];
+ outputClassDocSummary(c);
+ }
+ sumclasses = null;
+
+ // Output closing tag, finish output stream
+
+ println();
+ printCloseTag(0, "rootdoc");
+
+ closeTargetFile();
+
+ createIndexByName();
+
+
+
+ // Output information on all classes for which documentation
+ // has been made available via the Doclet API
+
+ println();
+ println(1, "<!-- Documentation for all classes -->");
+ ClassDoc[] classes = rootDoc.classes();
+ String prevPackageName = null;
+ for (int i = 0, ilim = classes.length; i < ilim; ++ i) {
+ ClassDoc c = classes[i];
+
+ if (isVerbose()) {
+ printNotice("Writing XML information for "+c.qualifiedName()+"...");
+ }
+ else {
+ String packageName = c.containingPackage().name();
+ if (null == prevPackageName || !packageName.equals(prevPackageName)) {
+ printNotice("Writing XML information for "+packageName+"...");
+ prevPackageName = packageName;
+ }
+ }
+
+ setTargetFile(c.qualifiedName().replace('/','.')+".xml");
+
+ println("<?xml version=\"1.0\"?>");
+ println("<!DOCTYPE gjdoc SYSTEM \"dtd/gjdoc.dtd\">");
+
+ outputClassDoc(c);
+
+ closeTargetFile();
+ }
+ classes = null;
+ }
+
+ // Copy DTD files to temporary directory
+
+ // FIXME: try to solve this via jar: URLs. but this will
+ // probably break libxmlj compatibility (?)
+
+ String[] resources = new String[] {
+ "gjdoc.dtd",
+ "gjdoc-alphaindex.dtd",
+ "dbcentx.mod",
+ "ent/iso-amsa.ent",
+ "ent/iso-amsb.ent",
+ "ent/iso-amsc.ent",
+ "ent/iso-amsn.ent",
+ "ent/iso-amso.ent",
+ "ent/iso-amsr.ent",
+ "ent/iso-box.ent",
+ "ent/iso-cyr1.ent",
+ "ent/iso-cyr2.ent",
+ "ent/iso-dia.ent",
+ "ent/iso-grk1.ent",
+ "ent/iso-grk2.ent",
+ "ent/iso-grk3.ent",
+ "ent/iso-grk4.ent",
+ "ent/iso-lat1.ent",
+ "ent/iso-lat2.ent",
+ "ent/iso-num.ent",
+ "ent/iso-pub.ent",
+ "ent/iso-tech.ent",
+ };
+
+ File tempDtdDirectory = new File(xmlTargetDirectory, "dtd");
+ File tempDtdEntDirectory = new File(tempDtdDirectory, "ent");
+
+ if ((tempDtdDirectory.exists() || tempDtdDirectory.mkdir())
+ && (tempDtdEntDirectory.exists() || tempDtdEntDirectory.mkdir())) {
+ for (int i = 0; i < resources.length; ++ i) {
+ copyResourceToFile("/dtd/" + resources[i],
+ new File(tempDtdDirectory, resources[i]));
+ }
+ }
+ else {
+ printError("Cannot create temporary directories for DTD data at " + tempDtdDirectory);
+ return false;
+ }
+
+ // Copy package data-dir directory
+
+ {
+ PackageDoc[] packages = rootDoc.specifiedPackages();
+ for (int i=0, ilim=packages.length; i<ilim; ++i) {
+ PackageDoc c = packages[i];
+ if (c instanceof GjdocPackageDoc) {
+ copyPackageDataDir((GjdocPackageDoc)c);
+ }
+ }
+ }
+
+ // All information has been output. Apply stylesheet if given.
+
+ gnu.classpath.tools.gjdoc.Main.releaseRootDoc();
+
+ this.currentClass = null;
+ this.currentMember = null;
+ this.currentExecMember = null;
+
+ System.gc();
+
+ // From this point we are only operating on files, so we don't
+ // need this anymore and can free up some memory
+
+ for (Iterator it = targets.iterator(); it.hasNext(); ) {
+
+ TargetContext target = (TargetContext)it.next();
+
+ // We have XSLT postprocessing, run DocTranslet.
+
+ //DocTranslet docTranslet = DocTranslet.fromClasspath("/doctranslets/html/gjdoc.xsl");
+
+ //docTranslet.setOptions(docTransletOptions);
+
+ target.getDocTranslet().setOptions(docTransletOptions);
+
+ target.getDocTranslet().apply(xmlTargetDirectory,
+ target.getTargetDirectory(),
+ rootDoc);
+ }
+
+ // Done
+
+ targets = null;
+
+ System.gc();
+ Runtime.getRuntime().runFinalization();
+
+ return true;
+ }
+ catch (Exception e) {
+
+ // Something went wrong. Report to stderr and pass error to
+ // Javadoc Reporter
+
+ e.printStackTrace();
+ printError(e.toString());
+
+ Throwable rootCause = e.getCause();
+ if (null != rootCause) {
+ while (null != rootCause.getCause()) {
+ rootCause = rootCause.getCause();
+ }
+ System.err.println("Root cause:");
+ rootCause.printStackTrace();
+ }
+
+ return false;
+ }
+ finally {
+
+ // In any case, delete the working directory if we created one
+
+ if (null != workingDirectory) {
+
+ if (!deleteRecursive(workingDirectory)) {
+ printWarning("Could not delete temporary directory at "+workingDirectory);
+ }
+ }
+
+ printNotice("Done.");
+ }
+ }
+
+ /**
+ * Recursively delete the specified directory and its contents,
+ * like <code>rm -Rf directory</code>
+ *
+ * @return <code>true</code> on success
+ */
+ private static boolean deleteRecursive(File directory) {
+
+ boolean success = true;
+
+ File[] files = directory.listFiles();
+
+ for (int i=0, ilim=files.length; i<ilim; ++i) {
+
+ File file = files[i];
+
+ if (file.isDirectory()) {
+
+ success = deleteRecursive(file) && success;
+ }
+ else {
+
+ success = file.delete() && success;
+ }
+ }
+
+ return directory.delete() && success;
+ }
+
+ /**
+ * Prints a string to stdout and appends a newline. Convenience
+ * method.
+ */
+ protected void println(String str) {
+ out.println(str);
+ }
+
+ /**
+ * Prints a string to stdout without appending a newline.
+ * Convenience method.
+ */
+ protected void print(String str) {
+ out.print(str);
+ }
+
+ /**
+ * In standard mode, prints an empty line to stdout.
+ * In thight mode, nothing happens.
+ * Convenience method.
+ */
+ protected void println() {
+ if (!compress) {
+ out.println();
+ }
+ }
+
+ /**
+ * In standard mode, prints the given text indented to stdout and appends newline.
+ * In tight mode, doesn't print indentation or newlines.
+ */
+ protected void print(int indentLevel, String msg) {
+ if (compress) {
+ out.print(msg);
+ }
+ else {
+ StringBuffer indentation = new StringBuffer();
+ for (int i=0; i<indentLevel*indentStep; ++i) {
+ indentation.append(' ');
+ }
+ out.print(indentation+msg);
+ }
+ }
+
+ /**
+ * In tight mode, prints a message at a given indentation level.
+ * In standard mode, appends a newline in addition.
+ */
+ protected void println(int indentLevel, String msg) {
+ print(indentLevel, msg);
+ if (!compress) out.println();
+ }
+
+ /**
+ * Prints an atom tag at the given indentation level.
+ */
+ protected void printAtomTag(int level, String tag) {
+ println(level, "<"+tagPrefix+":"+replaceCharsInTag(tag)+"/>");
+ }
+
+ /**
+ * Prints an open tag at the given indentation level.
+ */
+ protected void printOpenTag(int level, String tag) {
+ printOpenTag(level, replaceCharsInTag(tag), true);
+ }
+
+ /**
+ * Prints an open tag at the given indentation level and
+ * conditionally appends a newline (if not in tight mode).
+ */
+ protected void printOpenTag(int level, String tag, boolean appendNewline) {
+ if (appendNewline && !compress) {
+ println(level, "<"+tagPrefix+":"+replaceCharsInTag(tag)+">");
+ }
+ else {
+ print(level, "<"+tagPrefix+":"+replaceCharsInTag(tag)+">");
+ }
+ }
+
+ /**
+ * Prints a close tag at the given indentation level.
+ */
+ protected void printCloseTag(int level, String tag) {
+ printCloseTag(level, tag, true);
+ }
+
+ /**
+ * Prints a close tag at the given indentation level and
+ * conditionally appends a newline (if not in tight mode).
+ */
+ protected void printCloseTag(int level, String tag, boolean appendNewline) {
+ if (appendNewline && !compress) {
+ println(level, "</"+tagPrefix+":"+replaceCharsInTag(tag)+">");
+ }
+ else {
+ print(level, "</"+tagPrefix+":"+replaceCharsInTag(tag)+">");
+ }
+ }
+
+ public static int optionLength(String option) {
+ if ("-d".equals(option)) return 2;
+ else if ("-fixhtml".equals(option)) return 1;
+ else if ("-compress".equals(option)) return 1;
+ else if ("-nohtmlwarn".equals(option)) return 1;
+ else if ("-noemailwarn".equals(option)) return 1;
+ else if ("-indentstep".equals(option)) return 2;
+ else if ("-xslsheet".equals(option)) return 2;
+ else if ("-xsltdriver".equals(option)) return 2;
+ else if ("-postprocess".equals(option)) return 2;
+ else if ("-genhtml".equals(option)) return 1;
+ else if ("-geninfo".equals(option)) return 1;
+ else if ("-gendocbook".equals(option)) return 1;
+ else if ("-xmlonly".equals(option)) return 1;
+ else if ("-bottomnote".equals(option)) return 2;
+ else if ("-workpath".equals(option)) return 2;
+ else if ("-title".equals(option)) return 2;
+ else if ("-tagletpath".equals(option)) return 2;
+ else if ("-taglet".equals(option)) return 2;
+ else if ("-authormail".equals(option)) return 2;
+ else if ("-mailmangledot".equals(option)) return 2;
+ else if ("-mailmangleat".equals(option)) return 2;
+ else if ("-noindex".equals(option)) return 1;
+ else if ("-nocomment".equals(option)) return 1;
+ else if ("-notree".equals(option)) return 1;
+ else if ("-nohelp".equals(option)) return 1;
+ else if ("-nonavbar".equals(option)) return 1;
+ else if ("-splitindex".equals(option)) return 1;
+ else if ("-author".equals(option)) return 1;
+ else if ("-version".equals(option)) return 1;
+ else if ("-nosince".equals(option)) return 1;
+ else if ("-nodeprecated".equals(option)) return 1;
+ else if ("-linksource".equals(option)) return 1;
+ else if ("-windowtitle".equals(option)) return 2;
+ else if ("-helpfile".equals(option)) return 2;
+ else if ("-stylesheetfile".equals(option)) return 2;
+ else if ("-tag".equals(option)) return 2;
+ else if ("-header".equals(option)) return 2;
+ else if ("-footer".equals(option)) return 2;
+ else if ("-bottom".equals(option)) return 2;
+ else if ("-doctitle".equals(option)) return 2;
+ else if ("-nodeprecatedlist".equals(option)) return 1;
+ else if ("-uses".equals(option)) return 1;
+ else if ("-group".equals(option)) return 3;
+
+ else return -1;
+ }
+
+ public static boolean validOptions(String[][] options) {
+ return true;
+ }
+
+
+ /**
+ * Workaround for non well-formed comments: fix tag contents
+ * by replacing <code>&lt;</code> with <code>&amp;lt;</code>,
+ * <code>&gt;</code> with <code>&amp;gt;</code> and
+ * <code>&amp;</code> with <code>&amp;amp;</code>.
+ *
+ * @param tagContent String to process
+ *
+ * @return given String with all special characters replaced by
+ * HTML entities.
+ */
+ private static String replaceCharsInTag(String tagContent) {
+ return
+ replaceString(
+ replaceString(
+ replaceString(
+ tagContent,
+ "<", "&lt;"
+ ),
+ ">", "&gt;"
+ ),
+ "&", "&amp;"
+ );
+ }
+
+ /**
+ * Replaces all occurences of string <code>needle</code> within string
+ * <code>haystack</code> by string <code>replacement</code>.
+ *
+ * @param haystack The string to search and replace in.
+ * @param needle The string which is searched for.
+ * @param replacement The string by which every occurence of <code>needle</code> is replaced.
+ */
+ private static String replaceString(String haystack, String needle, String replacement) {
+ int ndx = haystack.indexOf(needle);
+ if (ndx<0)
+ return haystack;
+ else
+ return haystack.substring(0, ndx) + replacement
+ + replaceString(haystack.substring(ndx+needle.length()), needle, replacement);
+ }
+
+ protected void setTargetFile(String filename) throws IOException {
+
+ OutputStream fileOut = new FileOutputStream(new File(xmlTargetDirectory, filename));
+ out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fileOut, "UTF8")));;
+ }
+
+ protected void closeTargetFile() {
+
+ out.flush();
+ out.close();
+ }
+
+ private String cdata(String str) {
+
+ if (null==str) {
+ return str;
+ } // end of if ((null==str)
+
+ StringBuffer rc = new StringBuffer();
+ for (int i=0; i<str.length(); ++i) {
+ char c = str.charAt(i);
+ if (c==0x09 || c==0x0a || c==0x0d || (c>=0x20 && c<=0xd7ff) || (c>=0xe000 && c<=0xfffd) || (c>=0x10000 && c<=0x10ffff)) {
+ rc.append(c);
+ }
+ else {
+ printWarning("Invalid Unicode character 0x"+Integer.toString(c, 16)+" in javadoc markup has been stripped.");
+ } // end of else
+
+ }
+ return rc.toString();
+ }
+
+ static void copyResourceToFile(String resourceName, File target) throws IOException {
+
+ InputStream in = Driver.class.getResourceAsStream(resourceName);
+
+ if (null != in) {
+
+ FileOutputStream out = new FileOutputStream(target);
+ int size;
+ byte[] buffer = new byte[512];
+ while ((size = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, size);
+ }
+ out.close();
+ }
+ else {
+
+ throw new IOException("Can't find resource named "+resourceName);
+ }
+ }
+
+ private void printError(String error) {
+ if (null != rootDoc) {
+ rootDoc.printError(error);
+ }
+ else {
+ System.err.println("ERROR: "+error);
+ }
+ }
+
+ private void printWarning(String warning) {
+ if (null != rootDoc) {
+ rootDoc.printWarning(warning);
+ }
+ else {
+ System.err.println("WARNING: "+warning);
+ }
+ }
+
+ private void printNotice(String notice) {
+ if (null != rootDoc) {
+ rootDoc.printNotice(notice);
+ }
+ else {
+ System.err.println(notice);
+ }
+ }
+
+ /**
+ * Copy the contents of the input directory to the output
+ * directory. The output directory must exist.
+ */
+ private void copyPackageDataDir(GjdocPackageDoc packageDoc) throws IOException {
+ File docFilesSourceDirectory
+ = new File(packageDoc.packageDirectory(), "doc-files");
+ File docFilesTargetDirectory
+ = new File(this.targetDirectory,
+ packageDoc.name().replace('.', File.separatorChar));
+ if (docFilesSourceDirectory.exists()) {
+ printNotice("Copying files from " + docFilesSourceDirectory);
+ copyDirectory(docFilesSourceDirectory, docFilesTargetDirectory,
+ docFilesSubdirsEnabled,
+ excludeDocFilesSubDirs);
+ }
+ }
+
+ /**
+ * Recursively copy the contents of the input directory to the
+ * output directory. The output directory must exist.
+ */
+ private static void copyDirectory(File sourceDir, File targetDir,
+ boolean recursive,
+ Set excludeDirs) throws IOException {
+ if (!targetDir.exists() && !targetDir.mkdirs()) {
+ throw new IOException("Cannot create directory " + targetDir);
+ }
+
+ File[] sourceFiles = sourceDir.listFiles();
+ for (int i=0; i<sourceFiles.length; ++i) {
+ if (sourceFiles[i].isDirectory()) {
+ if (recursive && (null == excludeDirs
+ || !excludeDirs.contains(sourceFiles[i].getName()))) {
+ File targetSubDir = new File(targetDir,
+ sourceFiles[i].getName());
+ if (targetSubDir.exists() || targetSubDir.mkdir()) {
+ copyDirectory(sourceFiles[i], targetSubDir, recursive, null);
+ }
+ else {
+ throw new IOException("Cannot create directory " + targetSubDir);
+ }
+ }
+ }
+ else {
+ copyFile(sourceFiles[i], new File(targetDir, sourceFiles[i].getName()));
+ }
+ }
+ }
+
+ /**
+ * Copy the contents of the input file to the output file. The
+ * output file's parent directory must exist.
+ */
+ private static void copyFile(File sourceFile, File targetFile) throws IOException {
+
+ InputStream in = new FileInputStream(sourceFile);
+ OutputStream out = new FileOutputStream(targetFile);
+ int nread;
+ byte[] buf = new byte[512];
+ while ((nread = in.read(buf)) >= 0) {
+ out.write(buf, 0, nread);
+ }
+ in.close();
+ out.close();
+ }
+
+ private void createIndexByName() throws IOException {
+ // Create index
+
+ // Collect index
+
+ Map indexMap = new TreeMap(new Comparator() {
+ public int compare(Object o1, Object o2) {
+ return o1.toString().toLowerCase().compareTo(o2.toString().toLowerCase());
+ }
+ });
+
+ // Add packages to index
+
+ PackageDoc[] packages = rootDoc.specifiedPackages();
+ for (int i=0, ilim=packages.length; i<ilim; ++i) {
+ PackageDoc c = packages[i];
+ indexMap.put(c.name(), c);
+ }
+
+ // Add classes, fields and methods to index
+
+ ClassDoc[] sumclasses = rootDoc.classes();
+ for (int i=0, ilim=sumclasses.length; i<ilim; ++i) {
+ ClassDoc c = sumclasses[i];
+ if (null == c.containingClass()) {
+ indexMap.put(c.name(), c);
+ }
+ else {
+ indexMap.put(c.name().substring(c.containingClass().name().length() + 1), c);
+ }
+ FieldDoc[] fields = c.fields();
+ for (int j=0, jlim=fields.length; j<jlim; ++j) {
+ indexMap.put(fields[j].name(), fields[j]);
+ }
+ MethodDoc[] methods = c.methods();
+ for (int j=0, jlim=methods.length; j<jlim; ++j) {
+ MethodDoc method = methods[j];
+ StringBuffer signature = new StringBuffer();
+ signature.append(method.name());
+ signature.append('(');
+ Parameter[] parameters = method.parameters();
+ for (int k=0, klim=parameters.length; k<klim; ++k) {
+ if (k > 0) {
+ signature.append(", ");
+ }
+ signature.append(parameters[k].typeName());
+ }
+ signature.append(')');
+ indexMap.put(signature.toString(), method);
+ }
+ }
+
+ // Assign output stream
+
+ setTargetFile("alphaindex.xml");
+
+ // Output XML document header
+
+ println(0, "<?xml version=\"1.0\"?>");
+ println("<!DOCTYPE gjdoc SYSTEM \"dtd/gjdoc-alphaindex.dtd\">");
+ println();
+ printOpenTag(0, "alphaindex xmlns=\"http://www.w3.org/TR/REC-html40\" xmlns:gjdoc=\"http://www.gnu.org/software/cp-tools/gjdocxml\"");
+
+ Iterator it = indexMap.keySet().iterator();
+
+ char previousCategoryLetter = '\0';
+ boolean categoryOpen = false;
+
+ while (it.hasNext()) {
+ String key = (String)it.next();
+ Doc entry = (Doc)indexMap.get(key);
+
+ char firstChar = Character.toUpperCase(key.charAt(0));
+ if (firstChar != previousCategoryLetter) {
+ if (categoryOpen) {
+ printCloseTag(1, "category");
+ }
+ printOpenTag(1, "category letter=\"" + firstChar + "\"");
+ categoryOpen = true;
+ previousCategoryLetter = firstChar;
+ }
+
+ printOpenTag(2, "entry name=\"" + key + "\"");
+ if (entry instanceof PackageDoc) {
+ printAtomTag(3, "isPackage");
+ }
+ else if (entry instanceof ClassDoc) {
+ printAtomTag(3, "isClass");
+ ClassDoc centry = (ClassDoc)entry;
+ currentClass = centry;
+ printAtomTag(3, "containingPackage name=\"" + centry.containingPackage().name() + "\"");
+ if (null != centry.containingClass()) {
+ printAtomTag(3, "containingClass name=\"" + centry.containingClass().name() + "\"");
+ }
+ if (centry.isInterface()) {
+ printAtomTag(3, "isInterface");
+ }
+ if (centry.isException()) {
+ printAtomTag(3, "isException");
+ }
+ if (centry.isError()) {
+ printAtomTag(3, "isError");
+ }
+ if (centry.isOrdinaryClass()) {
+ printAtomTag(3, "isOrdinaryClass");
+ }
+ }
+ else if (entry instanceof ProgramElementDoc) {
+ ProgramElementDoc pentry = (ProgramElementDoc)entry;
+ currentClass = pentry.containingClass();
+ printAtomTag(3, "containingPackage name=\"" + pentry.containingPackage().name() + "\"");
+ printAtomTag(3, "containingClass name=\"" + pentry.containingClass().name() + "\"");
+ if (pentry.isMethod()) {
+ printAtomTag(3, "isMethod");
+ ExecutableMemberDoc mentry = (ExecutableMemberDoc)pentry;
+ printAtomTag(3, "signature full=\""+mentry.signature()+"\" flat=\""+mentry.flatSignature()+"\"");
+ printAtomTag(3, "method name=\"" + mentry.name() + "\"");
+ }
+ if (pentry.isField()) {
+ printAtomTag(3, "isField");
+ }
+ }
+
+ Tag[] tags = entry.firstSentenceTags();
+ for (int i=0, ilim=tags.length; i<ilim; ++i) {
+ Tag tag = tags[i];
+ if (tag.firstSentenceTags().length>0) {
+ printOpenTag(3, "firstSentenceTags", false);
+ outputTags(4, tag.firstSentenceTags(), false, CONTEXT_TYPE);
+ printCloseTag(3, "firstSentenceTags");
+ }
+ }
+
+
+ printCloseTag(2, "entry");
+ }
+
+ if (categoryOpen) {
+ printCloseTag(1, "category");
+ }
+
+ printCloseTag(0, "alphaindex");
+
+ closeTargetFile();
+ }
+
+ private static class UsageType
+ {
+ public static final UsageType CLASS_DERIVED_FROM = new UsageType("class-derived-from");
+ public static final UsageType FIELD_OF_TYPE = new UsageType("field-of-type");
+ public static final UsageType METHOD_WITH_RETURN_TYPE = new UsageType("method-with-return-type");
+ public static final UsageType METHOD_WITH_PARAMETER_TYPE = new UsageType("method-with-parameter-type");
+ public static final UsageType METHOD_WITH_THROWN_TYPE = new UsageType("method-with-thrown-type");
+ public static final UsageType CONSTRUCTOR_WITH_PARAMETER_TYPE = new UsageType("constructor-with-parameter-type");
+ public static final UsageType CONSTRUCTOR_WITH_THROWN_TYPE = new UsageType("constructor-with-thrown-type");
+ private String id;
+
+ private UsageType(String id)
+ {
+ this.id = id;
+ }
+
+ public String toString() {
+ return "UsageType{id=" + id + "}";
+ }
+
+ public String getId() {
+ return id;
+ }
+ }
+
+ /**
+ * ClassDoc -> (PackageDoc -> (UsageType -> (Set of Doc)))
+ */
+ private Map usedClassToPackagesMap = new HashMap();
+
+ private void addUsedBy(ClassDoc usedClass, UsageType usageType, Doc user, PackageDoc userPackage)
+ {
+ Map packageToUsageTypeMap = (Map)usedClassToPackagesMap.get(usedClass);
+ if (null == packageToUsageTypeMap) {
+ packageToUsageTypeMap = new HashMap();
+ usedClassToPackagesMap.put(usedClass, packageToUsageTypeMap);
+ }
+
+ Map usageTypeToUsersMap = (Map)packageToUsageTypeMap.get(userPackage);
+ if (null == usageTypeToUsersMap) {
+ usageTypeToUsersMap = new HashMap();
+ packageToUsageTypeMap.put(userPackage, usageTypeToUsersMap);
+ }
+
+ Set userSet = (Set)usageTypeToUsersMap.get(usageType);
+ if (null == userSet) {
+ userSet = new TreeSet(); // FIXME: we need the collator from Main here
+ usageTypeToUsersMap.put(usageType, userSet);
+ }
+ userSet.add(user);
+ }
+
+ /**
+ * Create the cross reference database.
+ */
+ private void collectUsage() {
+
+ ClassDoc[] classes = rootDoc.classes();
+ for (int i = 0, ilim = classes.length; i < ilim; ++ i) {
+ ClassDoc clazz = classes[i];
+
+ // classes derived from
+ for (ClassDoc superclass = clazz.superclass(); superclass != null;
+ superclass = superclass.superclass()) {
+ addUsedBy(superclass, UsageType.CLASS_DERIVED_FROM, clazz, clazz.containingPackage());
+ }
+
+ FieldDoc[] fields = clazz.fields();
+ for (int j = 0, jlim = fields.length; j < jlim; ++ j) {
+ FieldDoc field = fields[j];
+
+ // fields of type
+ ClassDoc fieldType = field.type().asClassDoc();
+ if (null != fieldType) {
+ addUsedBy(fieldType, UsageType.FIELD_OF_TYPE,
+ field, clazz.containingPackage());
+ }
+ }
+
+ MethodDoc[] methods = clazz.methods();
+ for (int j = 0, jlim = methods.length; j < jlim; ++ j) {
+ MethodDoc method = methods[j];
+
+ // methods with return type
+
+ ClassDoc returnType = method.returnType().asClassDoc();
+ if (null != returnType) {
+ addUsedBy(returnType, UsageType.METHOD_WITH_RETURN_TYPE,
+ method, clazz.containingPackage());
+ }
+ Parameter[] parameters = method.parameters();
+ for (int k=0; k<parameters.length; ++k) {
+
+ // methods with parameter type
+
+ Parameter parameter = parameters[k];
+ ClassDoc parameterType = parameter.type().asClassDoc();
+ if (null != parameterType) {
+ addUsedBy(parameterType, UsageType.METHOD_WITH_PARAMETER_TYPE,
+ method, clazz.containingPackage());
+ }
+ }
+
+ // methods which throw
+
+ ClassDoc[] thrownExceptions = method.thrownExceptions();
+ for (int k = 0, klim = thrownExceptions.length; k < klim; ++ k) {
+ ClassDoc thrownException = thrownExceptions[k];
+ addUsedBy(thrownException, UsageType.METHOD_WITH_THROWN_TYPE,
+ method, clazz.containingPackage());
+ }
+ }
+
+ ConstructorDoc[] constructors = clazz.constructors();
+ for (int j = 0, jlim = constructors.length; j < jlim; ++ j) {
+
+ ConstructorDoc constructor = constructors[j];
+
+ Parameter[] parameters = constructor.parameters();
+ for (int k = 0, klim = parameters.length; k < klim; ++ k) {
+
+ // constructors with parameter type
+
+ Parameter parameter = parameters[k];
+ ClassDoc parameterType = parameter.type().asClassDoc();
+ if (null != parameterType) {
+ addUsedBy(parameterType, UsageType.CONSTRUCTOR_WITH_PARAMETER_TYPE,
+ constructor, clazz.containingPackage());
+ }
+ }
+
+ // constructors which throw
+
+ ClassDoc[] thrownExceptions = constructor.thrownExceptions();
+ for (int k = 0, klim = thrownExceptions.length; k < klim; ++ k) {
+ ClassDoc thrownException = thrownExceptions[k];
+ addUsedBy(thrownException, UsageType.CONSTRUCTOR_WITH_THROWN_TYPE,
+ constructor, clazz.containingPackage());
+ }
+ }
+ }
+ }
+
+ private void outputUsage(ClassDoc clazz, int level) {
+
+ Map packageToUsageTypeMap = (Map)usedClassToPackagesMap.get(clazz);
+ if (null != packageToUsageTypeMap) {
+ printOpenTag(level, "references");
+
+ Iterator packagesIterator = packageToUsageTypeMap.keySet().iterator();
+
+ while (packagesIterator.hasNext()) {
+ PackageDoc packageDoc = (PackageDoc)packagesIterator.next();
+ printOpenTag(level + 1, "referencing-package name=\"" + packageDoc.name() + "\"");
+ Map usageTypeToUsersMap = (Map)packageToUsageTypeMap.get(packageDoc);
+ Iterator usageTypeIterator = usageTypeToUsersMap.keySet().iterator();
+ while (usageTypeIterator.hasNext()) {
+ UsageType usageType = (UsageType)usageTypeIterator.next();
+ printOpenTag(level + 2, "usage-type id=\"" + usageType.getId() + "\"");
+ Set users = (Set)usageTypeToUsersMap.get(usageType);
+ Iterator userIterator = users.iterator();
+ while (userIterator.hasNext()) {
+ Doc user = (Doc)userIterator.next();
+ if (user instanceof ClassDoc) {
+ printAtomTag(level + 3, "user"
+ + " class=\"" + ((ClassDoc)user).name() + "\"");
+ }
+ else if (user instanceof FieldDoc) {
+ FieldDoc fieldDoc = (FieldDoc)user;
+ printAtomTag(level + 3, "user"
+ + " class=\"" + fieldDoc.containingClass().name() + "\""
+ + " field=\"" + fieldDoc.name() + "\"");
+ }
+ else if (user instanceof MethodDoc) {
+ MethodDoc methodDoc = (MethodDoc)user;
+ printAtomTag(level + 3, "user"
+ + " class=\"" + methodDoc.containingClass().name() + "\""
+ + " method=\"" + methodDoc.name() + "\""
+ + " signature=\"" + methodDoc.signature() + "\""
+ + " flatSignature=\"" + methodDoc.flatSignature() + "\"");
+ }
+ else if (user instanceof ConstructorDoc) {
+ ConstructorDoc constructorDoc = (ConstructorDoc)user;
+ printAtomTag(level + 3, "user"
+ + " class=\"" + constructorDoc.containingClass().name() + "\""
+ + " signature=\"" + constructorDoc.signature() + "\""
+ + " flatSignature=\"" + constructorDoc.flatSignature() + "\"");
+ }
+ }
+ printCloseTag(level +2, "usage-type");
+ }
+ printCloseTag(level + 1, "referencing-package");
+ }
+
+ printCloseTag(level, "references");
+ }
+ }
+
+ private boolean processGroupOption(String groupName, String colonSeparatedPackageList)
+ {
+ try {
+ PackageMatcher packageMatcher = new PackageMatcher();
+
+ StringTokenizer tokenizer = new StringTokenizer(colonSeparatedPackageList, ":");
+ while (tokenizer.hasMoreTokens()) {
+ String packageWildcard = tokenizer.nextToken();
+ packageMatcher.addWildcard(packageWildcard);
+ }
+
+ SortedSet groupPackages = packageMatcher.filter(rootDoc.specifiedPackages());
+
+ packageGroups.add(new PackageGroup(groupName, groupPackages));
+
+ return true;
+ }
+ catch (InvalidPackageWildcardException e) {
+ return false;
+ }
+ }
+
+ private void registerTaglet(Taglet taglet)
+ {
+ tagletMap.put(taglet.getName(), taglet);
+ }
+
+ private boolean isVerbose()
+ {
+ return false;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver1_4.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver1_4.java
new file mode 100644
index 000000000..6744947af
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/Driver1_4.java
@@ -0,0 +1,84 @@
+/* gnu.classpath.tools.doclets.xmldoclet.Driver1_4
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet;
+
+import com.sun.javadoc.*;
+import java.io.IOException;
+
+/**
+ * A Doclet which retrieves all information presented by the Doclet
+ * API, dumping it to stdout in XML format.
+ *
+ * Supports Doclet API Version 1.4.
+ *
+ * @author Julian Scheid
+ */
+public class Driver1_4 extends Driver {
+
+ /**
+ * Official Doclet entry point.
+ */
+ public static boolean start(RootDoc root) {
+
+ // Create a new XmlDoclet instance and delegate control.
+ return new Driver1_4().instanceStart(root);
+ }
+
+ /* since 1.4
+ private void outputSourcePosition(int level, SourcePosition sourcePosition) {
+ println(level, "<sourceposition"
+ + " file=\""+sourcePosition.file().toString()+"\""
+ + " line=\""+sourcePosition.line()+"\""
+ + " column=\""+sourceposition.column()+"\""
+ + "/>");
+ }
+ */
+
+ protected void outputClassDoc(ClassDoc classDoc)
+ throws IOException
+ {
+ super.outputClassDoc(classDoc);
+ //outputSourcePosition(level, doc.position());
+ }
+
+ protected void outputFieldDocBody(int level, FieldDoc fieldDoc) {
+ super.outputFieldDocBody(level, fieldDoc);
+ //println(level, "<constantValueExpression>"+fieldDoc.constantValueExpression()+"</constantValueExpression>");
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/HtmlRepairer.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/HtmlRepairer.java
new file mode 100644
index 000000000..582a45b32
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/HtmlRepairer.java
@@ -0,0 +1,690 @@
+/* gnu.classpath.tools.doclets.xmldoclet.HtmlRepairer.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet;
+
+import java.io.*;
+import java.util.*;
+import com.sun.javadoc.DocErrorReporter;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.MemberDoc;
+
+/**
+ * Provides methods for tidying up HTML source.
+ *
+ * @author Julian Scheid
+ */
+public final class HtmlRepairer {
+
+ private static class TagInfo {
+
+ private Set parentTags = new HashSet();
+
+ public TagInfo(String parentTag) {
+ this.parentTags.add(parentTag);
+ }
+
+ public TagInfo(String[] parentTagArr) {
+ for (int i=0; i<parentTagArr.length; ++i) {
+ this.parentTags.add(parentTagArr[i]);
+ }
+ }
+
+ public boolean isLegalParentTag(String tag) {
+ return this.parentTags.contains(tag);
+ }
+ }
+
+ private DocErrorReporter warningReporter;
+ private boolean noWarn;
+ private boolean noEmailWarn;
+ private ClassDoc contextClass;
+ private MemberDoc contextMember;
+ private StringBuffer output = new StringBuffer();
+ private Stack tagStack = new Stack();
+ private boolean isLeadingTag = true;
+ private boolean throwAwayLeadingPara = false;
+
+ private static Map tagInfoMap;
+
+ private static Set noTextParentTags;
+
+ static {
+ tagInfoMap = new HashMap();
+ tagInfoMap.put("li", new TagInfo(new String[] { "ul", "ol", "nl", "menu", "dir" }));
+ tagInfoMap.put("td", new TagInfo(new String[] { "tr" }));
+ tagInfoMap.put("th", new TagInfo(new String[] { "tr" }));
+ tagInfoMap.put("tr", new TagInfo(new String[] { "table" }));
+ tagInfoMap.put("dt", new TagInfo(new String[] { "dl" }));
+ tagInfoMap.put("dd", new TagInfo(new String[] { "dl" }));
+ tagInfoMap.put("param", new TagInfo(new String[] { "applet" }));
+
+ String[] noTextParentTagArr = {
+ "area", "base", "body", "br", "dd", "dt", "head", "hr", "html",
+ "img", "input", "link", "map", "meta", "ol", "optgroup", "param",
+ "select", "table", "tbody", "tfoot", "thead", "tr", "ul",
+ };
+
+ noTextParentTags = new HashSet();
+ for (int i=0; i<noTextParentTagArr.length; ++i) {
+ noTextParentTags.add(noTextParentTagArr[i]);
+ }
+ }
+
+ public HtmlRepairer(DocErrorReporter warningReporter,
+ boolean noWarn, boolean noEmailWarn,
+ ClassDoc contextClass, MemberDoc contextMember,
+ boolean throwAwayLeadingPara) {
+ this.warningReporter = warningReporter;
+ this.noWarn = noWarn;
+ this.noEmailWarn = noEmailWarn;
+ this.contextClass = contextClass;
+ this.contextMember = contextMember;
+ this.throwAwayLeadingPara = throwAwayLeadingPara;
+ }
+
+ private static String replaceStr(String haystack, String needle, String replacement) {
+ int ndx=haystack.indexOf(needle);
+ if (ndx<0)
+ return haystack;
+ else
+ return haystack.substring(0, ndx)+replacement
+ + replaceStr(haystack.substring(ndx+needle.length()), needle, replacement);
+ }
+
+ private void haveText(String text) {
+
+ if (isLeadingTag && throwAwayLeadingPara) {
+ if (0 != text.trim().length()) {
+ isLeadingTag = false;
+ }
+ }
+
+ if (tagStack.isEmpty() || !noTextParentTags.contains(tagStack.peek())) {
+
+ text = replaceStr(text, "&lt1", "&lt;1");
+ text = replaceStr(text, "&&", "&amp;&amp;");
+ text = replaceStr(text, "& ", "&amp; ");
+ text = replaceStr(text, "&\t", "&amp;\t");
+ text = replaceStr(text, "&\r", "&amp;\r");
+ text = replaceStr(text, "&\n", "&amp;\n");
+ for (char c='0'; c<='9'; ++c)
+ text = replaceStr(text, "&"+c, "&amp;"+c);
+ text = replaceStr(text, "\u00a7", "&sect;");
+ output.append(text);
+ }
+ else {
+ printWarning("Discarded text in <" + tagStack.peek() + "> element");
+ }
+ }
+
+ private void haveStartOrEndTag(String tag) {
+
+ boolean _isLeadingTag = isLeadingTag;
+ isLeadingTag = false;
+
+ tag = tag.trim();
+
+ boolean isEndTag = tag.startsWith("/");
+ boolean isAtomTag = tag.endsWith("/");
+
+ if (isEndTag && isAtomTag) {
+ // got something like '</a/>' which is invalid.
+ // suppose a close tag was intended.
+ tag = tag.substring(0, tag.length()-1);
+ }
+
+ if (tag.length() < 1) {
+ printWarning("Deleting broken tag");
+ return;
+ }
+
+ String tagName = tag.substring(isEndTag?1:0, isAtomTag?tag.length()-1:tag.length());
+ String tagAttributes = "";
+
+ for (int i=0; i<tagName.length(); ++i) {
+ if (" \t\r\n".indexOf(tagName.charAt(i))>=0) {
+ tagAttributes = tagName.substring(i).trim();
+ tagName = tagName.substring(0, i);
+ break;
+ }
+ }
+
+ if (!isEndTag && tagName.indexOf('@')>0) {
+ if (!noEmailWarn) {
+ printWarning("Tag looks like email address: <"+tagName+">");
+ }
+ output.append("&lt;"+tag+"&gt;");
+ return;
+ }
+
+ tagName = tagName.toLowerCase();
+
+ if (_isLeadingTag && "p".equals(tagName) && !isEndTag && throwAwayLeadingPara) {
+ return;
+ }
+
+ if ("p".equals(tagName) || "br".equals(tagName) || "hr".equals(tagName)) {
+ // throw away </p> and </br>
+ if (isEndTag) {
+ return;
+ }
+ // make sure every <p> is a <p/> and every <br> is a <br/>
+ else if (!isAtomTag) {
+ tag += "/";
+ isAtomTag = true;
+ }
+ }
+
+ if (isEndTag) {
+
+ // check whether this close tag is on the stack
+ // if yes, close all tags up to this tag
+ if (tagStack.contains(tagName)) {
+ String popped;
+ do {
+ popped = (String)tagStack.pop();
+ if (!popped.equals(tagName))
+ printWarning("Inserting '</"+popped+">");
+ output.append("</"+popped+">");
+ }
+ while (!popped.equals(tagName));
+ }
+ // if not, just throw it away
+ else {
+ printWarning("Deleting <"+tag+">");
+ }
+ }
+ else {
+
+ final int STATE_INITIAL = 1;
+ final int STATE_EXPECT_ATTRIBUTENAME = 2;
+ final int STATE_UNQUOTED_ATTRIBUTEVALUE = 3;
+ final int STATE_SINGLEQUOTE_ATTRIBUTEVALUE = 4;
+ final int STATE_DOUBLEQUOTE_ATTRIBUTEVALUE = 5;
+ final int STATE_EXPECT_ATTRIBUTEVALUE = 6;
+ final int STATE_EXPECT_EQUALSIGN = 7;
+
+ int state = STATE_INITIAL;
+
+ String newAttributes = "";
+ String attributeName = null;
+ StringBuffer buf = new StringBuffer();
+
+ char[] attrsAsChars = tagAttributes.toCharArray();
+ for (int i=0, ilim=attrsAsChars.length+1; i<ilim; ++i) {
+ int c;
+ if (i<attrsAsChars.length)
+ c = (int)attrsAsChars[i];
+ else
+ c = -1;
+
+ switch (state) {
+
+ case STATE_INITIAL:
+ if (" \t\r\n".indexOf(c)>=0){
+ continue;
+ }
+ else if (-1==c) {
+ continue;
+ }
+ else {
+ state = STATE_EXPECT_ATTRIBUTENAME;
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_EXPECT_ATTRIBUTENAME:
+ if ('='==c) {
+ attributeName = buf.toString();
+ buf.setLength(0);
+ state = STATE_EXPECT_ATTRIBUTEVALUE;
+ }
+ else if (-1==c) {
+ attributeName = buf.toString();
+ buf.setLength(0);
+ printWarning("In Tag '"+tag+"':\nAttribute name without a value, inserting value =\""+attributeName+"\"");
+ }
+ else if (" \t\r\n".indexOf(c)>=0) {
+ state = STATE_EXPECT_EQUALSIGN;
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_EXPECT_EQUALSIGN:
+ if (" \t\r\n".indexOf(c)>=0){
+ continue;
+ }
+ else if ('='==c) {
+ state = STATE_EXPECT_ATTRIBUTEVALUE;
+ attributeName = buf.toString();
+ buf.setLength(0);
+ }
+ else {
+ attributeName = buf.toString();
+ buf.setLength(0);
+ printWarning("In Tag '"+tag+"':\nAttribute name without a value, inserting value =\""+attributeName+"\"");
+ newAttributes += " "+attributeName+"=\""+attributeName+"\"";
+ buf.append((char)c);
+ state = STATE_EXPECT_ATTRIBUTENAME;
+ }
+ break;
+
+ case STATE_EXPECT_ATTRIBUTEVALUE:
+ if (" \t\r\n".indexOf(c)>=0){
+ continue;
+ }
+ else if ('\"'==c) {
+ state = STATE_DOUBLEQUOTE_ATTRIBUTEVALUE;
+ }
+ else if ('\''==c) {
+ state = STATE_SINGLEQUOTE_ATTRIBUTEVALUE;
+ }
+ else {
+ state = STATE_UNQUOTED_ATTRIBUTEVALUE;
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_UNQUOTED_ATTRIBUTEVALUE:
+ if (-1==c || " \t\r\n".indexOf(c)>=0){
+ state = STATE_INITIAL;
+ newAttributes += " "+attributeName + "=\"" + buf.toString() + "\"";
+ buf.setLength(0);
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_SINGLEQUOTE_ATTRIBUTEVALUE:
+ if ('\''==c) {
+ state = STATE_INITIAL;
+ newAttributes += " "+attributeName + "=\"" + buf.toString() + "\"";
+ buf.setLength(0);
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_DOUBLEQUOTE_ATTRIBUTEVALUE:
+ if ('\"'==c) {
+ state = STATE_INITIAL;
+ newAttributes += " "+attributeName + "=\"" + buf.toString() + "\"";
+ buf.setLength(0);
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+ }
+ }
+
+
+ if (!isAtomTag) {
+
+ // check whether this open tag is equal to the topmost
+ // entry on the stack; if yes, emit a close tag first
+
+ // corrects stuff like '<tr><td>...<td>...');
+ if (!tagStack.isEmpty() && tagStack.peek().equals(tagName)) {
+ printWarning("Inserting </"+tagName+">");
+ output.append("</"+tagName+">");
+ tagStack.pop();
+ }
+ else {
+ processKnownChildTags(tagName, tagStack, output);
+ }
+
+ // otherwise, we assume there are no close tags required
+ // before this open tag.
+ tagStack.push(tagName);
+
+ output.append("<"+tagName+newAttributes+">");
+ }
+ else {
+ output.append("<"+tagName+newAttributes+"/>");
+ }
+ }
+ }
+
+ private boolean processKnownChildTags(String tagName, Stack tagStack, StringBuffer output) {
+
+ TagInfo tagInfo = (TagInfo)tagInfoMap.get(tagName);
+ if (null != tagInfo) {
+
+ String parentTag = null;
+ for (Enumeration en = tagStack.elements(); en.hasMoreElements(); ) {
+ String tag = (String)en.nextElement();
+ if (tagInfo.isLegalParentTag(tag)) {
+ parentTag = tag;
+ break;
+ }
+ }
+ if (parentTag != null) {
+ while (((String)tagStack.peek()) != parentTag) {
+ String poppedTagName = (String)tagStack.pop();
+ output.append("</"+poppedTagName+">");
+ printWarning("Inserting </"+poppedTagName+">");
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void flush() {
+
+ // close all pending tags
+ while (!tagStack.isEmpty()) {
+ String tagName = (String)tagStack.pop();
+ printWarning("Inserting </"+tagName+">");
+ output.append("</"+tagName+">");
+ }
+ }
+
+ /**
+ * Takes HTML fragment and returns a well-formed XHTML
+ * equivalent.
+ *
+ * In the returned String, all tags are properly closed and
+ * nested.
+ *
+ * Currently, the returned String is not guaranteed to be
+ * well-formed. In particular there are no checks on the tag
+ * names, attribute names and entity names.
+ */
+ public String getWellformedHTML(String text) {
+
+ final int STATE_INITIAL = 1;
+ final int STATE_TAG_START = 2;
+ final int STATE_TAG = 3;
+ final int STATE_TAG_DOUBLEQUOTE = 4;
+ final int STATE_TAG_SINGLEQUOTE = 5;
+ final int STATE_AMP = 6;
+
+ int state = STATE_INITIAL;
+ output.setLength(0);
+
+
+ StringBuffer buf = new StringBuffer();
+ char[] textAsChars = text.toCharArray();
+
+ outer_loop:
+ for (int i=0, ilim=textAsChars.length+1; i<ilim; ++i) {
+ int c;
+
+ if (i<textAsChars.length) {
+ c = textAsChars[i];
+ }
+ else {
+ c = -1;
+ }
+
+ switch (state) {
+
+ case STATE_INITIAL:
+ if ('<'==c) {
+ state = STATE_TAG_START;
+ if (buf.length()>0) {
+ haveText(buf.toString());
+ buf.setLength(0);
+ }
+ }
+ else if ('>'==c) {
+ // assume this is a greater-than sign
+ buf.append("&gt;");
+ }
+ else if ('&'==c) {
+ state = STATE_AMP;
+ }
+ else if (-1==c) {
+ if (buf.length()>0) {
+ haveText(buf.toString());
+ buf.setLength(0);
+ }
+ continue;
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_AMP:
+ if ('<'==c) {
+ buf.append("&amp;");
+ state = STATE_TAG_START;
+ if (buf.length()>0) {
+ haveText(buf.toString());
+ buf.setLength(0);
+ }
+ }
+ else if ('>'==c) {
+ // assume this is a greater-than sign
+ buf.append("&amp;");
+ buf.append("&gt;");
+ state = STATE_INITIAL;
+ }
+ else if ('&'==c) {
+ buf.append("&amp;");
+ buf.append("&amp;");
+ state = STATE_INITIAL;
+ }
+ else if (-1==c) {
+ buf.append("&amp;");
+ haveText(buf.toString());
+ buf.setLength(0);
+ state = STATE_INITIAL;
+ continue;
+ }
+ else {
+ // peek forward and see whether this is a valid entity.
+ if ('#'==c) {
+ buf.append("&");
+ buf.append((char)c);
+ state = STATE_INITIAL;
+ continue outer_loop;
+ }
+ else if (Character.isLetter((char)c)) {
+ for (int i2=i+1; i2<ilim-1; i2++) {
+ if (';' == textAsChars[i2]) {
+ buf.append("&");
+ buf.append((char)c);
+ state = STATE_INITIAL;
+ continue outer_loop;
+ }
+ else if (!Character.isLetter((char)c)
+ && !Character.isDigit((char)c)
+ && ".-_:".indexOf((char)c) < 0
+ //&& !isCombiningChar(c) // FIXME
+ //&& !isExtender(c) // FIXME
+ ) {
+ break;
+ }
+ }
+ // not a valid entity declaration; assume &amp;
+ }
+ buf.append("&amp;");
+ buf.append((char)c);
+ state = STATE_INITIAL;
+ }
+
+ /*
+ else if ('#'==c || Character.isLetter((char)c)) {
+ buf.append("&");
+ buf.append((char)c);
+ state = STATE_INITIAL;
+ }
+ else {
+ buf.append("&amp;");
+ buf.append((char)c);
+ state = STATE_INITIAL;
+ }
+ */
+ break;
+
+ case STATE_TAG_START:
+ if (" \t\r\n".indexOf(c)>=0) {
+ //continue;
+
+ // new: assume this is a less-sign
+ haveText("&lt;"+c);
+ state = STATE_INITIAL;
+ }
+ else if ('/'==c) {
+ buf.append((char)c);
+ state = STATE_TAG;
+ }
+ else if ('<'==c) {
+ // assume this is a less-sign
+ haveText("&lt;&lt;");
+ state = STATE_INITIAL;
+ }
+ else if ('>'==c) {
+ // assume this is a less-sign
+ haveText("&lt;&gt;");
+ state = STATE_INITIAL;
+ }
+ //else if ('-'==c || '+'==c || '='==c || '\''==c || "0123456789".indexOf(c)>=0) {
+ else if (!Character.isLetter((char)c)) {
+ // assume this is a less-sign
+ haveText("&lt;"+(char)c);
+ state = STATE_INITIAL;
+ }
+ else {
+ buf.append((char)c);
+ state = STATE_TAG;
+ }
+ break;
+
+ case STATE_TAG:
+ if ('\"'==c) {
+ buf.append((char)c);
+ state = STATE_TAG_DOUBLEQUOTE;
+ }
+ else if ('\''==c) {
+ buf.append((char)c);
+ state = STATE_TAG_SINGLEQUOTE;
+ }
+ else if ('>'==c) {
+ state = STATE_INITIAL;
+ haveStartOrEndTag(buf.toString());
+ buf.setLength(0);
+ }
+ else if ('<'==c) {
+ // notify user, missing greater-than sign
+ haveStartOrEndTag(buf.toString());
+ buf.setLength(0);
+ }
+ else if (-1==c) {
+ printWarning("Unclosed tag at end-of-comment: <"+buf);
+ haveStartOrEndTag(buf.toString());
+ buf.setLength(0);
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_TAG_DOUBLEQUOTE:
+ if ('\"'==c) {
+ buf.append((char)c);
+ state = STATE_TAG;
+ }
+ else if (-1==c) {
+ printWarning("Unclosed attribute value at end-of-comment.");
+ haveStartOrEndTag(buf.toString()+"\"");
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+
+ case STATE_TAG_SINGLEQUOTE:
+ if ('\''==c) {
+ buf.append((char)c);
+ state = STATE_TAG;
+ }
+ else if (-1==c) {
+ printWarning("Unclosed attribute value at end-of-comment.");
+ haveStartOrEndTag(buf.toString()+"'");
+ }
+ else {
+ buf.append((char)c);
+ }
+ break;
+ }
+ }
+
+ return output.toString();
+ }
+
+ private String getContext() {
+ if (null != contextClass) {
+ StringBuffer rc = new StringBuffer();
+ rc.append(contextClass.qualifiedTypeName());
+ if (null != contextMember) {
+ rc.append("."+contextMember.toString());
+ }
+ return rc.toString();
+ }
+ else {
+ return null;
+ }
+ }
+
+ private void printWarning(String msg) {
+ if (null != warningReporter && !noWarn) {
+ String context = getContext();
+ if (null != context) {
+ warningReporter.printWarning("In "+getContext()+": "+msg);
+ }
+ else {
+ warningReporter.printWarning("In overview page: "+msg);
+ }
+ }
+ }
+
+ public String terminateText() {
+ output.setLength(0);
+ flush();
+ return output.toString();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/TargetContext.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/TargetContext.java
new file mode 100644
index 000000000..6e05a5e96
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/TargetContext.java
@@ -0,0 +1,103 @@
+/* gnu.classpath.tools.doclets.xmldoclet.TargetContext
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import java.net.URL;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+
+import gnu.classpath.tools.doclets.xmldoclet.doctranslet.DocTranslet;
+
+/**
+ * Stores any XSL transformation and postprocessing-specific
+ * information given by the user on the doclet command line.
+ *
+ * @author Julian Scheid
+ */
+public class TargetContext {
+
+ /**
+ * The DocTranslet to use for processing doclet output.
+ */
+ private DocTranslet docTranslet;
+
+ /**
+ * Directory to write final output to.
+ */
+ private File targetDirectory;
+
+ /**
+ * Directory where XSLT output will be written to. If an XSLT
+ * sheet was specified, but no postprocessing driver was given,
+ * this is the target directory specified by the user. Otherwise,
+ * this is a temporary directory.
+ */
+ private File xsltTargetDirectory;
+
+
+ public TargetContext(DocTranslet docTranslet, File targetDirectory) {
+ this.docTranslet = docTranslet;
+ this.targetDirectory = targetDirectory;
+ }
+
+ public File getTargetDirectory() {
+ return targetDirectory;
+ }
+
+ public void setTargetDirectory(File targetDirectory) {
+ this.targetDirectory = targetDirectory;
+ }
+
+ public DocTranslet getDocTranslet() {
+ return docTranslet;
+ }
+
+ public void setDocTranslet(DocTranslet docTranslet) {
+ this.docTranslet = docTranslet;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTranslet.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTranslet.java
new file mode 100644
index 000000000..c5a9f82b9
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTranslet.java
@@ -0,0 +1,460 @@
+/* gnu.classpath.tools.doclets.xmldoclet.doctranslet.DocTranslet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet.doctranslet;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.URIResolver;
+
+import javax.xml.transform.dom.DOMResult;
+
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.xml.sax.SAXException;
+
+import gnu.classpath.tools.IOToolkit;
+import gnu.classpath.tools.doclets.xmldoclet.Driver;
+
+import com.sun.javadoc.DocErrorReporter;
+
+public class DocTranslet implements ErrorListener {
+
+ private static class DocErrorReporterOutputStream
+ extends OutputStream
+ {
+ private ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private DocErrorReporter reporter;
+
+ public DocErrorReporterOutputStream(DocErrorReporter reporter) {
+ this.reporter = reporter;
+ }
+
+ public void write(int ch) {
+ out.write(ch);
+ if (ch == 10) {
+ reporter.printNotice(out.toString());
+ out.reset();
+ }
+ }
+ }
+
+ private String mainResourceFilename;
+ private ClassLoader classLoader;
+ private Map transformerMap = new java.util.HashMap(); //WeakHashMap();
+ private DocTransletOptions options;
+
+ protected DocTranslet(String mainResourceFilename,
+ ClassLoader classLoader)
+ throws DocTransletConfigurationException {
+
+ if (mainResourceFilename.length() > 0 && mainResourceFilename.charAt(0) == '/') {
+ mainResourceFilename = mainResourceFilename.substring(1);
+ }
+ this.mainResourceFilename = mainResourceFilename;
+ this.classLoader = classLoader;
+ }
+
+ private static boolean equalsFile(File file1, File file2) {
+ return file1.getAbsolutePath().equals(file2.getAbsolutePath());
+ }
+
+ private static File getParentFile(File file) {
+ String filename = file.getAbsolutePath();
+ if (filename.endsWith(File.separator)) {
+ filename = filename.substring(0, filename.length() - 1);
+ }
+ int lastSlash = filename.lastIndexOf(File.separatorChar);
+ if (lastSlash > 0) {
+ filename = filename.substring(0, lastSlash);
+ }
+ else {
+ filename = File.separator;
+ }
+
+ return new File(filename);
+ }
+
+ private static boolean cacheXSLTSheets = true;
+
+ public void apply(File xmlSourceDirectory, File targetDirectory,
+ DocErrorReporter reporter)
+ throws DocTransletException {
+
+ PrintStream err = System.err;
+
+ try{
+ URL mainResourceURL = classLoader == null ?
+ ClassLoader.getSystemResource(mainResourceFilename):
+ classLoader.getResource(mainResourceFilename);
+
+ if (null == mainResourceURL) {
+ throw new DocTransletException("Cannot find resource '" + mainResourceFilename + "'");
+ }
+
+
+ Map parameters = new HashMap();
+ parameters.put("gjdoc.xmldoclet.version", Driver.XMLDOCLET_VERSION);
+
+ parameters.put("gjdoc.option.nonavbar", xsltBoolean(options.nonavbar));
+ parameters.put("gjdoc.option.noindex", xsltBoolean(options.noindex));
+ parameters.put("gjdoc.option.notree", xsltBoolean(options.notree));
+ parameters.put("gjdoc.option.nocomment", xsltBoolean(options.nocomment));
+ parameters.put("gjdoc.option.nohelp", xsltBoolean(options.nohelp));
+ parameters.put("gjdoc.option.splitindex", xsltBoolean(options.splitindex));
+ parameters.put("gjdoc.option.linksource", xsltBoolean(options.linksource));
+ parameters.put("gjdoc.option.nodeprecatedlist", xsltBoolean(options.nodeprecatedlist));
+ parameters.put("gjdoc.option.uses", xsltBoolean(options.uses));
+ parameters.put("gjdoc.option.windowtitle", options.windowtitle);
+ parameters.put("gjdoc.option.helpfile", options.helpfile);
+ parameters.put("gjdoc.option.stylesheetfile", options.stylesheetfile);
+ parameters.put("gjdoc.option.header", options.header);
+ parameters.put("gjdoc.option.footer", options.footer);
+ parameters.put("gjdoc.option.bottom", options.bottom);
+ parameters.put("gjdoc.option.doctitle", options.doctitle);
+
+ List outputFileList = getOutputFileList(mainResourceURL,
+ xmlSourceDirectory,
+ parameters);
+
+ reporter.printNotice("Running DocTranslet...");
+
+ TransformerFactory transformerFactory
+ = TransformerFactory.newInstance();
+
+ transformerFactory.setErrorListener(this);
+
+ boolean isLibxmlJ
+ = transformerFactory.getClass().getName().equals("gnu.xml.libxmlj.transform.TransformerFactoryImpl");
+
+ for (Iterator it = outputFileList.iterator(); it.hasNext(); ) {
+
+ if (isLibxmlJ) {
+ System.gc();
+ Runtime.getRuntime().runFinalization();
+ }
+
+ OutputFileInfo fileInfo = (OutputFileInfo)it.next();
+
+ File targetFile = new File(targetDirectory, fileInfo.getName());
+ File packageTargetDir = getParentFile(targetFile);
+
+ if (!packageTargetDir.exists() && !packageTargetDir.mkdirs()) {
+ throw new DocTransletException("Target directory " + packageTargetDir + " does not exist and cannot be created.");
+ }
+
+ if (options.linksource) {
+ File sourceTargetDirectory = new File(targetDirectory, "src-html");
+ File sourceTargetFile = new File(sourceTargetDirectory, fileInfo.getName());
+ File sourcePackageTargetDir = getParentFile(sourceTargetFile);
+
+ if (!sourcePackageTargetDir.exists() && !sourcePackageTargetDir.mkdirs()) {
+ throw new DocTransletException("Target directory " + packageTargetDir + " does not exist and cannot be created.");
+ }
+ }
+
+ if (options.uses) {
+ File usesTargetDirectory = new File(targetDirectory, "class-use");
+ File usesTargetFile = new File(usesTargetDirectory, fileInfo.getName());
+ File usesPackageTargetDir = getParentFile(usesTargetFile);
+
+ if (!usesPackageTargetDir.exists() && !usesPackageTargetDir.mkdirs()) {
+ throw new DocTransletException("Target directory " + packageTargetDir + " does not exist and cannot be created.");
+ }
+ }
+
+ if (null != fileInfo.getSource()) {
+
+ reporter.printNotice("Copying " + fileInfo.getComment() + "...");
+ InputStream in = new URL(mainResourceURL, fileInfo.getSource()).openStream();
+ FileOutputStream out = new FileOutputStream(targetFile.getAbsolutePath());
+ IOToolkit.copyStream(in, out);
+ in.close();
+ out.close();
+ }
+ else {
+
+ reporter.printNotice("Generating " + fileInfo.getComment() + "...");
+
+ String pathToRoot = "";
+ for (File file = getParentFile(targetFile); !equalsFile(file, targetDirectory); file = getParentFile(file)) {
+ pathToRoot += "../";
+ }
+
+ StreamResult out = new StreamResult(targetFile.getAbsolutePath());
+
+ StreamSource in = new StreamSource(new File(xmlSourceDirectory, "index.xml").getAbsolutePath());
+ URL resource = new URL(mainResourceURL, fileInfo.getSheet());
+
+
+ StreamSource xsltSource = new StreamSource(resource.toExternalForm());
+
+ if (null != fileInfo.getInfo()) {
+ parameters.put("gjdoc.outputfile.info", fileInfo.getInfo());
+ }
+ parameters.put("gjdoc.pathtoroot", pathToRoot);
+
+ Transformer transformer;
+ transformer = (Transformer)transformerMap.get(xsltSource.getSystemId());
+ if (null == transformer) {
+ transformer = transformerFactory.newTransformer(xsltSource);
+ if (cacheXSLTSheets) {
+ transformerMap.put(xsltSource.getSystemId(), transformer);
+ }
+ }
+
+ transformer.clearParameters();
+ for (Iterator pit = parameters.keySet().iterator(); pit.hasNext(); ) {
+ String key = (String)pit.next();
+ String value = (String)parameters.get(key);
+ transformer.setParameter(key, value);
+ }
+
+ transformer.setErrorListener(this);
+ DocErrorReporterOutputStream errorReporterOut
+ = new DocErrorReporterOutputStream(reporter);
+ System.setErr(new PrintStream(errorReporterOut));
+
+ transformer.transform(in, out);
+ errorReporterOut.flush();
+ }
+ }
+ }
+ catch (MalformedURLException e) {
+ throw new DocTransletException(e);
+ }
+ catch (TransformerFactoryConfigurationError e) {
+ throw new DocTransletException(e);
+ }
+ catch (TransformerException e) {
+ throw new DocTransletException(e.getMessageAndLocation(), e);
+ }
+ catch (IOException e) {
+ throw new DocTransletException(e);
+ }
+ finally {
+ System.setErr(err);
+ }
+ }
+
+ private List getOutputFileList(URL resource, File xmlSourceDirectory, Map parameters)
+ throws DocTransletException {
+
+ try {
+ List result;
+
+ OutputStream out = new ByteArrayOutputStream();
+
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document document = documentBuilder.newDocument();
+ DOMResult domResult = new DOMResult(document);
+ {
+ StreamSource source = new StreamSource(resource.toExternalForm());
+
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = (Transformer)transformerFactory.newTransformer(source);
+
+ transformer.clearParameters();
+ for (Iterator pit = parameters.keySet().iterator(); pit.hasNext(); ) {
+ String key = (String)pit.next();
+ String value = (String)parameters.get(key);
+ transformer.setParameter(key, value);
+ }
+
+ transformer.transform(new StreamSource(new File(xmlSourceDirectory,
+ "index.xml").getAbsolutePath()),
+ domResult);
+ }
+
+ {
+ NodeList nodeList = document.getElementsByTagName("outputfile");
+ result = new ArrayList(nodeList.getLength());
+
+ for (int i=0; i<nodeList.getLength(); ++i) {
+ Element elem = (Element)nodeList.item(i);
+ String name = getTextContent(elem.getElementsByTagName("name").item(0));
+ String source
+ = (null != elem.getElementsByTagName("source").item(0))
+ ? getTextContent(elem.getElementsByTagName("source").item(0))
+ : null;
+ String sheet
+ = (null != elem.getElementsByTagName("sheet").item(0))
+ ? getTextContent(elem.getElementsByTagName("sheet").item(0))
+ : null;
+ String comment = getTextContent(elem.getElementsByTagName("comment").item(0));
+ String info = null;
+ if (elem.getElementsByTagName("info").getLength() > 0) {
+ if (null != elem.getElementsByTagName("info").item(0).getFirstChild()) {
+ info = getTextContent(elem.getElementsByTagName("info").item(0));
+ }
+ else {
+ info = "";
+ }
+ }
+ result.add(new OutputFileInfo(name, source, sheet, comment, info));
+ }
+ }
+ return result;
+ }
+ catch (TransformerFactoryConfigurationError e) {
+ throw new DocTransletException(e);
+ }
+ catch (TransformerException e) {
+ throw new DocTransletException(e.getMessageAndLocation(), e);
+ }
+ catch (ParserConfigurationException e) {
+ throw new DocTransletException(e);
+ }
+ }
+
+ private String getTextContent(Node elem)
+ {
+ StringBuffer result = new StringBuffer();
+ NodeList children = elem.getChildNodes();
+ for (int i=0; i<children.getLength(); ++i) {
+ Node item = children.item(i);
+ if (null != item) {
+ String value = item.getNodeValue();
+ if (null != value) {
+ result.append(value);
+ }
+ }
+ }
+ return result.toString();
+ }
+
+ public void setOptions(DocTransletOptions options) {
+ this.options = options;
+ }
+
+
+ public static DocTranslet fromClasspath(String resourceName)
+ throws DocTransletConfigurationException {
+
+ return new DocTranslet(resourceName,
+ DocTranslet.class.getClassLoader());
+ }
+
+ public static DocTranslet fromJarFile(File jarFile)
+ throws DocTransletConfigurationException {
+
+ try {
+ JarFile inputJarFile = new JarFile(jarFile, false, JarFile.OPEN_READ);
+
+ Manifest manifest = inputJarFile.getManifest();
+
+ if (null == manifest) {
+
+ throw new DocTransletConfigurationException("Jar file '" + jarFile + "' doesn't contain a manifest.");
+ }
+
+ Attributes mainAttributes = manifest.getMainAttributes();
+
+ String docTransletMainEntry = mainAttributes.getValue("doctranslet-main-entry");
+
+ if (null == docTransletMainEntry) {
+
+ throw new DocTransletConfigurationException("Manifest in Jar file '" + jarFile + "' doesn't contain a doctranslet-main-entry specification.");
+ }
+
+ return new DocTranslet(docTransletMainEntry,
+ new JarClassLoader(inputJarFile));
+ }
+ catch (IOException e) {
+ throw new DocTransletConfigurationException(e);
+ }
+ }
+
+ private static String xsltBoolean(boolean b) {
+ return b ? "1" : "";
+ }
+
+ public void error (TransformerException exception)
+ throws TransformerException {
+
+ throw exception;
+ }
+
+ public void fatalError (TransformerException exception)
+ throws TransformerException {
+
+ throw exception;
+ }
+
+ public void warning (TransformerException exception)
+ throws TransformerException {
+
+ System.err.println("WWW: " + exception.getMessage());
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletConfigurationException.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletConfigurationException.java
new file mode 100644
index 000000000..092d0cea7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletConfigurationException.java
@@ -0,0 +1,53 @@
+/* gnu.classpath.tools.doclets.xmldoclet.doctranslet.DocTransletConfigurationException
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet.doctranslet;
+
+public class DocTransletConfigurationException extends Exception {
+
+ public DocTransletConfigurationException(String msg) {
+ super(msg);
+ }
+
+ public DocTransletConfigurationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ public DocTransletConfigurationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletException.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletException.java
new file mode 100644
index 000000000..96ffefa0f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletException.java
@@ -0,0 +1,63 @@
+/* gnu.classpath.tools.doclets.xmldoclet.doctranslet.DocTransletException
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet.doctranslet;
+
+public class DocTransletException extends Exception {
+
+ public DocTransletException(String msg) {
+ super(msg);
+ }
+
+ private void initCauseDynamic(Throwable cause)
+ {
+ try {
+ getClass().getMethod("initCause", new Class[]{Throwable.class}).invoke(this, new Object[] { cause });
+ }
+ catch (Exception ignore) {
+ }
+ }
+
+ public DocTransletException(String msg, Throwable cause) {
+ super(msg);
+ initCauseDynamic(cause);
+ }
+
+ public DocTransletException(Throwable cause) {
+ initCauseDynamic(cause);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletOptions.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletOptions.java
new file mode 100644
index 000000000..5c99ec3bd
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/DocTransletOptions.java
@@ -0,0 +1,62 @@
+/* gnu.classpath.tools.doclets.xmldoclet.doctranslet.DocTransletOptions
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet.doctranslet;
+
+/**
+ * Value class for carrying command line options which need to be
+ * passed through to the stylesheets.
+ */
+public class DocTransletOptions
+{
+ public boolean nonavbar;
+ public boolean noindex;
+ public boolean notree;
+ public boolean nocomment;
+ public boolean nohelp;
+ public boolean splitindex;
+ public boolean linksource;
+ public boolean nodeprecatedlist;
+ public boolean uses;
+ public String windowtitle = "";
+ public String helpfile = "";
+ public String stylesheetfile = "";
+ public String header = "";
+ public String footer = "";
+ public String bottom = "";
+ public String doctitle = "";
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/JarClassLoader.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/JarClassLoader.java
new file mode 100644
index 000000000..b7b100be1
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/JarClassLoader.java
@@ -0,0 +1,91 @@
+/* gnu.classpath.tools.doclets.xmldoclet.doctranslet.JarClassLoader
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet.doctranslet;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.util.jar.JarFile;
+import java.util.jar.JarEntry;
+
+public class JarClassLoader extends ClassLoader {
+
+ private JarFile jarFile;
+
+ public JarClassLoader(JarFile jarFile) {
+ this.jarFile = jarFile;
+ }
+
+ public Class findClass(String name)
+ throws ClassNotFoundException {
+
+ byte[] b = loadClassData(name);
+ return defineClass(name, b, 0, b.length);
+ }
+
+ private byte[] loadClassData(String className)
+ throws ClassNotFoundException
+ {
+ String classFileName = className.replace('.', File.separatorChar) + ".class";
+
+ try {
+ JarEntry jarEntry = jarFile.getJarEntry(classFileName);
+ if (null != jarEntry) {
+ return readFromStream(jarFile.getInputStream(jarEntry),
+ jarEntry.getSize());
+ }
+ }
+ catch (IOException ignore_) {
+ }
+ throw new ClassNotFoundException(className);
+ }
+
+ private byte[] readFromStream(InputStream in, long size)
+ throws IOException
+ {
+ byte[] result = new byte[(int)size];
+ int nread = 0;
+ int offset = 0;
+ while (offset < size && (nread = in.read(result, offset, (int)(size - offset))) >= 0) {
+ offset += nread;
+ }
+ in.close();
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/OutputFileInfo.java b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/OutputFileInfo.java
new file mode 100644
index 000000000..b0ede615d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/doclets/xmldoclet/doctranslet/OutputFileInfo.java
@@ -0,0 +1,66 @@
+/* gnu.classpath.tools.doclets.xmldoclet.doctranslet.OutputFileInfo
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.doclets.xmldoclet.doctranslet;
+
+/**
+ * Holds information about a file to be generated by the DocTranslet.
+ */
+public class OutputFileInfo {
+
+ private String name;
+ private String source;
+ private String sheet;
+ private String comment;
+ private String info;
+
+ public OutputFileInfo(String name, String source, String sheet, String comment, String info) {
+ this.name = name;
+ this.source = source;
+ this.sheet = sheet;
+ this.comment = comment;
+ this.info = info;
+ }
+
+ public String getName() { return name; }
+ public String getSource() { return source; }
+ public String getSheet() { return sheet; }
+ public String getComment() { return comment; }
+ public String getInfo() { return info; }
+
+ public String toString() { return "OutputFileInfo{name="+name+",source="+source+",sheet="+sheet+",comment="+comment+",info="+info+"}"; }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java b/libjava/classpath/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java
new file mode 100644
index 000000000..53a4f3d1d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java
@@ -0,0 +1,62 @@
+/* FileArgumentCallback.java - handle non-option command line arguments
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.getopt;
+
+/**
+ * This is a callback class which is used when a "file name" is found by the
+ * command-line parser. A file name is any command-line argument which does not
+ * start with a dash and which is not the argument of some preceding option.
+ */
+public abstract class FileArgumentCallback
+{
+ /**
+ * Create a new instance.
+ */
+ protected FileArgumentCallback()
+ {
+ }
+
+ /**
+ * This is called when a file argument is seen.
+ *
+ * @param fileArgument the file name
+ */
+ public abstract void notifyFile(String fileArgument)
+ throws OptionException;
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/getopt/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/getopt/Messages.java
new file mode 100644
index 000000000..19f101743
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/getopt/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- i18n support for getopt
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.getopt;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.getopt.Messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/getopt/Option.java b/libjava/classpath/tools/gnu/classpath/tools/getopt/Option.java
new file mode 100644
index 000000000..e7b5d82e7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/getopt/Option.java
@@ -0,0 +1,266 @@
+/* Option.java - represent a command-line option
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.getopt;
+
+/**
+ * This is the base class representing an option. An option can have a short
+ * form. This is a single character, like '-x'. An option can have a long form,
+ * like '--verbose'; if the parser is working in "long option only" mode, then a
+ * long flag has a single dash, like '-verbose'. Both a long and a short form
+ * may be specified; it is not valid to have neither. A description is mandatory
+ * for options; this is used to automatically generate '--help' output. An option
+ * which takes an argument and which has a short form can also be "joined", in
+ * this case the option's argument can either be separated, like "-I path" or
+ * joined with the short option name, like "-Ipath".
+ */
+public abstract class Option
+{
+ private char shortName;
+
+ private String longName;
+
+ private String description;
+
+ private String argumentName;
+
+ private boolean joined;
+
+ /**
+ * Create a new option with the given short name and description.
+ *
+ * @param shortName the short name
+ * @param description the description
+ */
+ protected Option(char shortName, String description)
+ {
+ if (shortName == 0)
+ throw new IllegalArgumentException("short name must not be \\0");
+ this.shortName = shortName;
+ this.description = description;
+ }
+
+ /**
+ * Create a new option with the given short name and description.
+ *
+ * @param shortName the short name
+ * @param description the description
+ * @param argumentName the descriptive name of the argument, if this option
+ * takes an argument; otherwise null
+ */
+ protected Option(char shortName, String description, String argumentName)
+ {
+ if (shortName == 0)
+ throw new IllegalArgumentException("short name must not be \\0");
+ this.shortName = shortName;
+ this.description = description;
+ this.argumentName = argumentName;
+ }
+
+ /**
+ * Create a new option with the given short name and description.
+ *
+ * @param shortName the short name
+ * @param description the description
+ * @param argumentName the descriptive name of the argument, if this option
+ * takes an argument; otherwise null
+ * @param joined true if the short option is joined to its argument
+ */
+ protected Option(char shortName, String description, String argumentName,
+ boolean joined)
+ {
+ if (shortName == 0)
+ throw new IllegalArgumentException("short name must not be \\0");
+ this.shortName = shortName;
+ this.description = description;
+ this.argumentName = argumentName;
+ this.joined = joined;
+ }
+
+ /**
+ * Create a new option with the given long name and description. The long name
+ * should be specified without any leading dashes.
+ *
+ * @param longName the long name
+ * @param description the description
+ */
+ protected Option(String longName, String description)
+ {
+ this.longName = longName;
+ this.description = description;
+ }
+
+ /**
+ * Create a new option with the given long name and description. The long name
+ * should be specified without any leading dashes.
+ *
+ * @param longName the long name
+ * @param description the description
+ * @param argumentName the descriptive name of the argument, if this option
+ * takes an argument; otherwise null
+ */
+ protected Option(String longName, String description, String argumentName)
+ {
+ this.longName = longName;
+ this.description = description;
+ this.argumentName = argumentName;
+ }
+
+ /**
+ * Create a new option with the given short and long names and description.
+ * The long name should be specified without any leading dashes.
+ *
+ * @param longName the long name
+ * @param shortName the short name
+ * @param description the description
+ */
+ protected Option(String longName, char shortName, String description)
+ {
+ if (shortName == 0)
+ throw new IllegalArgumentException("short name must not be \\0");
+ this.shortName = shortName;
+ this.longName = longName;
+ this.description = description;
+ }
+
+ /**
+ * Create a new option with the given short and long names and description.
+ * The long name should be specified without any leading dashes.
+ *
+ * @param longName the long name
+ * @param shortName the short name
+ * @param description the description
+ * @param argumentName the descriptive name of the argument, if this option
+ * takes an argument; otherwise null
+ */
+ protected Option(String longName, char shortName, String description,
+ String argumentName)
+ {
+ if (shortName == 0)
+ throw new IllegalArgumentException("short name must not be \\0");
+ this.shortName = shortName;
+ this.longName = longName;
+ this.argumentName = argumentName;
+ this.description = description;
+ }
+
+ /**
+ * Create a new option with the given short and long names and description.
+ * The long name should be specified without any leading dashes.
+ *
+ * @param longName the long name
+ * @param shortName the short name
+ * @param description the description
+ * @param argumentName the descriptive name of the argument, if this option
+ * takes an argument; otherwise null
+ * @param joined true if the short option is joined to its argument
+ */
+ protected Option(String longName, char shortName, String description,
+ String argumentName, boolean joined)
+ {
+ if (shortName == 0)
+ throw new IllegalArgumentException("short name must not be \\0");
+ this.shortName = shortName;
+ this.longName = longName;
+ this.argumentName = argumentName;
+ this.description = description;
+ this.joined = joined;
+ }
+
+ /**
+ * Return the short name of the option, or \0 if none.
+ */
+ public char getShortName()
+ {
+ return shortName;
+ }
+
+ /**
+ * Return the long name of the option, or null if none.
+ */
+ public String getLongName()
+ {
+ return longName;
+ }
+
+ /**
+ * Return true if the argument takes an option.
+ */
+ public boolean getTakesArgument()
+ {
+ return argumentName != null;
+ }
+
+ /**
+ * Return the name of the argument. If the option does not take an argument,
+ * returns null.
+ */
+ public String getArgumentName()
+ {
+ return argumentName;
+ }
+
+ /**
+ * Return the description of the option.
+ */
+ public String getDescription()
+ {
+ return description;
+ }
+
+ /**
+ * Return true if this is a "joined" option, false otherwise.
+ * Only the short form of an option can be joined; this will always
+ * return false for an option which does not have a short form.
+ */
+ public boolean isJoined()
+ {
+ return joined;
+ }
+
+ /**
+ * This is called by the parser when this option is recognized. It may be
+ * called multiple times during a single parse. If this option takes an
+ * argument, the argument will be passed in. Otherwise the argument will be
+ * null.
+ *
+ * @param argument the argument
+ * @throws OptionException if the option or its argument is somehow invalid
+ */
+ public abstract void parsed(String argument) throws OptionException;
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/getopt/OptionException.java b/libjava/classpath/tools/gnu/classpath/tools/getopt/OptionException.java
new file mode 100644
index 000000000..2d7f77a55
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/getopt/OptionException.java
@@ -0,0 +1,58 @@
+/* OptionException.java - when command-line processing fails
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.getopt;
+
+/**
+ * An OptionException is thrown internally when an error is seen when parsing a
+ * command line.
+ */
+public class OptionException
+ extends Exception
+{
+ public OptionException(String message)
+ {
+ super(message);
+ }
+
+ public OptionException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/getopt/OptionGroup.java b/libjava/classpath/tools/gnu/classpath/tools/getopt/OptionGroup.java
new file mode 100644
index 000000000..83fcca0f8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/getopt/OptionGroup.java
@@ -0,0 +1,268 @@
+/* OptionGroup.java - a group of related command-line options
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.getopt;
+
+import java.io.PrintStream;
+import java.text.BreakIterator;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+
+/**
+ * An option group holds a collection of Options. It also has a name. Option
+ * groups are primarily useful for grouping help output.
+ */
+public class OptionGroup
+{
+ /** An 80-character string of whitespaces to use as a source for padding. */
+ private static final String FILLER = " "
+ + " ";
+ private String name;
+
+ ArrayList options = new ArrayList();
+
+ /**
+ * Create a new nameless option group. This can only be used by Parser.
+ */
+ OptionGroup()
+ {
+ }
+
+ /**
+ * Create a new option group with the indicated name.
+ *
+ * @param name the name
+ */
+ public OptionGroup(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Print a designated text to a {@link PrintStream}, eventually wrapping the
+ * lines of text so as to ensure that the width of each line does not overflow
+ * {@link Parser#MAX_LINE_LENGTH} columns. The line-wrapping is done with a
+ * {@link BreakIterator} using the default {@link Locale}.
+ * <p>
+ * The text to print may contain <code>\n</code> characters. This method will
+ * force a line-break for each such character.
+ *
+ * @param out the {@link PrintStream} destination of the formatted text.
+ * @param text the text to print.
+ * @param leftMargin a positive value indicating the column position of the
+ * start of the first line. Continuation lines, if they exist, are
+ * printed starting at <code>leftMargin + 2</code> as per GNU
+ * convention.
+ * @see Parser#MAX_LINE_LENGTH
+ */
+ protected static void formatText(PrintStream out, String text, int leftMargin)
+ {
+ formatText(out, text, leftMargin, Locale.getDefault());
+ }
+
+ /**
+ * Similar to the method with the same name and three arguments, except that
+ * the caller MUST specify a non-null {@link Locale} instance.
+ * <p>
+ * Print a designated text to a {@link PrintStream}, eventually wrapping the
+ * lines of text so as to ensure that the width of each line does not overflow
+ * {@link Parser#MAX_LINE_LENGTH} columns. The line-wrapping is done with a
+ * {@link BreakIterator} using the designated {@link Locale}.
+ * <p>
+ * The text to print may contain <code>\n</code> characters. This method will
+ * force a line-break for each such character.
+ *
+ * @param out the {@link PrintStream} destination of the formatted text.
+ * @param text the text to print.
+ * @param leftMargin a positive value indicating the column position of the
+ * start of the first line. Continuation lines, if they exist, are
+ * printed starting at <code>leftMargin + 2</code> as per GNU
+ * convention.
+ * @param aLocale the {@link Locale} instance to use when constructing the
+ * {@link BreakIterator}.
+ * @see Parser#MAX_LINE_LENGTH
+ */
+ protected static void formatText(PrintStream out, String text, int leftMargin,
+ Locale aLocale)
+ {
+ BreakIterator bit = BreakIterator.getLineInstance(aLocale);
+ String[] lines = text.split("\n");
+ int length = leftMargin;
+ String leftPadding = FILLER.substring(0, leftMargin + 2);
+ for (int i = 0; i < lines.length; i++)
+ {
+ text = lines[i];
+ bit.setText(text);
+ int start = bit.first();
+ int finish;
+ while ((finish = bit.next()) != BreakIterator.DONE)
+ {
+ String word = text.substring(start, finish);
+ length += word.length();
+ if (length >= Parser.MAX_LINE_LENGTH)
+ {
+ out.println();
+ out.print(leftPadding);
+ length = word.length() + leftMargin + 2;
+ }
+ out.print(word);
+ start = finish;
+ }
+ out.println();
+ if (i != lines.length - 1)
+ {
+ length = leftMargin + 2;
+ out.print(leftPadding);
+ }
+ }
+ }
+
+ /**
+ * Add an option to this option group.
+ *
+ * @param opt the option to add
+ */
+ public void add(Option opt)
+ {
+ options.add(opt);
+ }
+
+ /**
+ * Print the help output for this option group.
+ *
+ * @param out the stream to which to print
+ */
+ public void printHelp(PrintStream out, boolean longOnly)
+ {
+ // Compute maximum lengths.
+ int maxArgLen = 0;
+ boolean shortOptionSeen = false;
+ Iterator it;
+
+ // The first pass only looks to see if we have a short option.
+ it = options.iterator();
+ while (it.hasNext())
+ {
+ Option option = (Option) it.next();
+ if (option.getShortName() != '\0')
+ {
+ shortOptionSeen = true;
+ break;
+ }
+ }
+
+ it = options.iterator();
+ while (it.hasNext())
+ {
+ Option option = (Option) it.next();
+ String argName = option.getArgumentName();
+ // First compute the width required for the short
+ // option. "2" is the initial indentation. In the
+ // GNU style we don't print an argument name for
+ // a short option if there is also a long name for
+ // the option.
+ int thisArgLen = 2;
+ if (shortOptionSeen)
+ thisArgLen += 4;
+ if (option.getLongName() != null)
+ {
+ // Handle either '-' or '--'.
+ thisArgLen += 1 + option.getLongName().length();
+ if (! longOnly)
+ ++thisArgLen;
+ }
+ // Add in the width of the argument name.
+ if (argName != null)
+ thisArgLen += 1 + argName.length();
+ maxArgLen = Math.max(maxArgLen, thisArgLen);
+ }
+
+ // Print the help.
+ if (name != null)
+ out.println(name + ":");
+ it = options.iterator();
+ while (it.hasNext())
+ {
+ Option option = (Option) it.next();
+ String argName = option.getArgumentName();
+ int column = 0;
+ if (option.getShortName() != '\0')
+ {
+ out.print(" -");
+ out.print(option.getShortName());
+ column += 4;
+ if (option.getLongName() == null)
+ {
+ if (argName != null)
+ {
+ if (! option.isJoined())
+ {
+ out.print(' ');
+ ++column;
+ }
+ out.print(argName);
+ column += argName.length();
+ }
+ out.print(" ");
+ }
+ else
+ out.print(", ");
+ column += 2;
+ }
+ // Indent the long option past the short options, if one
+ // was seen.
+ for (; column < (shortOptionSeen ? 6 : 2); ++column)
+ out.print(' ');
+ if (option.getLongName() != null)
+ {
+ out.print(longOnly ? "-" : "--");
+ out.print(option.getLongName());
+ column += (longOnly ? 1 : 2) + option.getLongName().length();
+ if (argName != null)
+ {
+ out.print(" " + argName);
+ column += 1 + argName.length();
+ }
+ }
+ // FIXME: should have a better heuristic for padding.
+ out.print(FILLER.substring(0, maxArgLen + 4 - column));
+ formatText(out, option.getDescription(), maxArgLen + 4);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/getopt/Parser.java b/libjava/classpath/tools/gnu/classpath/tools/getopt/Parser.java
new file mode 100644
index 000000000..f23250eca
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/getopt/Parser.java
@@ -0,0 +1,495 @@
+/* Parser.java - parse command line options
+ Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.getopt;
+
+import java.io.PrintStream;
+import java.text.BreakIterator;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+
+/**
+ * An instance of this class is used to parse command-line options. It does "GNU
+ * style" argument recognition and also automatically handles "--help" and
+ * "--version" processing. It can also be put in "long option only" mode. In
+ * this mode long options are recognized with a single dash (as well as a double
+ * dash) and strings of options like "-abc" are never parsed as a collection of
+ * short options.
+ */
+public class Parser
+{
+ /** The maximum right column position. */
+ public static final int MAX_LINE_LENGTH = 80;
+
+ private String programName;
+
+ private String headerText;
+
+ private String footerText;
+
+ private boolean longOnly;
+
+ // All of the options. This is null initially; users must call
+ // requireOptions before access.
+ private ArrayList options;
+
+ private ArrayList optionGroups = new ArrayList();
+
+ private OptionGroup defaultGroup = new OptionGroup();
+
+ private OptionGroup finalGroup;
+
+ // These are used while parsing.
+ private int currentIndex;
+
+ private String[] args;
+
+ /**
+ * Create a new parser. The program name is used when printing error messages.
+ * The version string is printed verbatim in response to "--version".
+ *
+ * @param programName the name of the program
+ * @param versionString the program's version information
+ */
+ public Parser(String programName, String versionString)
+ {
+ this(programName, versionString, false);
+ }
+
+ /**
+ * Print a designated text to a {@link PrintStream}, eventually wrapping the
+ * lines of text so as to ensure that the width of each line does not overflow
+ * {@link #MAX_LINE_LENGTH} columns. The line-wrapping is done with a
+ * {@link BreakIterator} using the default {@link Locale}.
+ * <p>
+ * The text to print may contain <code>\n</code> characters. This method will
+ * force a line-break for each such character.
+ *
+ * @param out the {@link PrintStream} destination of the formatted text.
+ * @param text the text to print.
+ * @see Parser#MAX_LINE_LENGTH
+ */
+ protected static void formatText(PrintStream out, String text)
+ {
+ formatText(out, text, Locale.getDefault());
+ }
+
+ /**
+ * Similar to the method with the same name and two arguments, except that the
+ * caller MUST specify a non-null {@link Locale} instance.
+ * <p>
+ * Print a designated text to a {@link PrintStream}, eventually wrapping the
+ * lines of text so as to ensure that the width of each line does not overflow
+ * {@link #MAX_LINE_LENGTH} columns. The line-wrapping is done with a
+ * {@link BreakIterator} using the designated {@link Locale}.
+ * <p>
+ * The text to print may contain <code>\n</code> characters. This method will
+ * force a line-break for each such character.
+ *
+ * @param out the {@link PrintStream} destination of the formatted text.
+ * @param text the text to print.
+ * @param aLocale the {@link Locale} instance to use when constructing the
+ * {@link BreakIterator}.
+ * @see Parser#MAX_LINE_LENGTH
+ */
+ protected static void formatText(PrintStream out, String text, Locale aLocale)
+ {
+ BreakIterator bit = BreakIterator.getLineInstance(aLocale);
+ String[] lines = text.split("\n"); //$NON-NLS-1$
+ for (int i = 0; i < lines.length; i++)
+ {
+ text = lines[i];
+ bit.setText(text);
+ int length = 0;
+ int finish;
+ int start = bit.first();
+ while ((finish = bit.next()) != BreakIterator.DONE)
+ {
+ String word = text.substring(start, finish);
+ length += word.length();
+ if (length >= MAX_LINE_LENGTH)
+ {
+ out.println();
+ length = word.length();
+ }
+ out.print(word);
+ start = finish;
+ }
+ out.println();
+ }
+ }
+
+ /**
+ * Create a new parser. The program name is used when printing error messages.
+ * The version string is printed verbatim in response to "--version".
+ *
+ * @param programName the name of the program
+ * @param versionString the program's version information
+ * @param longOnly true if the parser should work in long-option-only mode
+ */
+ public Parser(String programName, final String versionString, boolean longOnly)
+ {
+ this.programName = programName;
+ this.longOnly = longOnly;
+
+ // Put standard options in their own section near the end.
+ finalGroup = new OptionGroup(Messages.getString("Parser.StdOptions")); //$NON-NLS-1$
+ finalGroup.add(new Option("help", Messages.getString("Parser.PrintHelp")) //$NON-NLS-1$ //$NON-NLS-2$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ printHelp(System.out);
+ System.exit(0);
+ }
+ });
+ finalGroup.add(new Option("version", Messages.getString("Parser.PrintVersion")) //$NON-NLS-1$ //$NON-NLS-2$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ System.out.println(versionString);
+ System.exit(0);
+ }
+ });
+ add(finalGroup);
+
+ add(defaultGroup);
+ }
+
+ /**
+ * Set the header text that is printed by --help.
+ *
+ * @param headerText the header text
+ */
+ public synchronized void setHeader(String headerText)
+ {
+ this.headerText = headerText;
+ }
+
+ /**
+ * Set the footer text that is printed by --help.
+ *
+ * @param footerText the footer text
+ */
+ public synchronized void setFooter(String footerText)
+ {
+ this.footerText = footerText;
+ }
+
+ /**
+ * Add an option to this parser. The option is added to the default option
+ * group; this affects where it is placed in the help output.
+ *
+ * @param opt the option
+ */
+ public synchronized void add(Option opt)
+ {
+ defaultGroup.add(opt);
+ }
+
+ /**
+ * This is like {@link #add(Option)}, but adds the option to the "final"
+ * group. This should be used sparingly, if at all; it is intended for
+ * other very generic options like --help or --version.
+ * @param opt the option to add
+ */
+ protected synchronized void addFinal(Option opt)
+ {
+ finalGroup.add(opt);
+ }
+
+ /**
+ * Add an option group to this parser. All the options in this group will be
+ * recognized by the parser.
+ *
+ * @param group the option group
+ */
+ public synchronized void add(OptionGroup group)
+ {
+ // This ensures that the final group always appears at the end
+ // of the options.
+ if (optionGroups.isEmpty())
+ optionGroups.add(group);
+ else
+ optionGroups.add(optionGroups.size() - 1, group);
+ }
+
+ // Make sure the 'options' field is properly initialized.
+ private void requireOptions()
+ {
+ if (options != null)
+ return;
+ options = new ArrayList();
+ Iterator it = optionGroups.iterator();
+ while (it.hasNext())
+ {
+ OptionGroup group = (OptionGroup) it.next();
+ options.addAll(group.options);
+ }
+ }
+
+ public void printHelp()
+ {
+ this.printHelp(System.out);
+ }
+
+ synchronized void printHelp(PrintStream out)
+ {
+ requireOptions();
+
+ if (headerText != null)
+ {
+ formatText(out, headerText);
+ out.println();
+ }
+
+ Iterator it = optionGroups.iterator();
+ while (it.hasNext())
+ {
+ OptionGroup group = (OptionGroup) it.next();
+ // An option group might be empty, in which case we don't
+ // want to print it..
+ if (! group.options.isEmpty())
+ {
+ group.printHelp(out, longOnly);
+ out.println();
+ }
+ }
+
+ if (footerText != null)
+ formatText(out, footerText);
+ }
+
+ /**
+ * This method can be overridden by subclassses to provide some option
+ * validation. It is called by the parser after all options have been
+ * parsed. If an option validation problem is encountered, this should
+ * throw an {@link OptionException} whose message should be shown to
+ * the user.
+ * <p>
+ * It is better to do validation here than after {@link #parse(String[])}
+ * returns, because the parser will print a message referring the
+ * user to the <code>--help</code> option.
+ * <p>
+ * The base implementation does nothing.
+ *
+ * @throws OptionException the error encountered
+ */
+ protected void validate() throws OptionException
+ {
+ // Base implementation does nothing.
+ }
+
+ private String getArgument(String request) throws OptionException
+ {
+ ++currentIndex;
+ if (currentIndex >= args.length)
+ {
+ String message
+ = MessageFormat.format(Messages.getString("Parser.ArgReqd"), //$NON-NLS-1$
+ new Object[] { request });
+ throw new OptionException(request);
+ }
+ return args[currentIndex];
+ }
+
+ private void handleLongOption(String real, int index) throws OptionException
+ {
+ String option = real.substring(index);
+ String justName = option;
+ int eq = option.indexOf('=');
+ if (eq != -1)
+ justName = option.substring(0, eq);
+ boolean isPlainShort = justName.length() == 1;
+ char shortName = justName.charAt(0);
+ Option found = null;
+ for (int i = options.size() - 1; i >= 0; --i)
+ {
+ Option opt = (Option) options.get(i);
+ if (justName.equals(opt.getLongName()))
+ {
+ found = opt;
+ break;
+ }
+ if ((isPlainShort || opt.isJoined())
+ && opt.getShortName() == shortName)
+ {
+ if (! isPlainShort)
+ {
+ // The rest of the option string is the argument.
+ eq = 0;
+ }
+ found = opt;
+ break;
+ }
+ }
+ if (found == null)
+ {
+ String msg = MessageFormat.format(Messages.getString("Parser.Unrecognized"), //$NON-NLS-1$
+ new Object[] { real });
+ throw new OptionException(msg);
+ }
+ String argument = null;
+ if (found.getTakesArgument())
+ {
+ if (eq == -1)
+ argument = getArgument(real);
+ else
+ argument = option.substring(eq + 1);
+ }
+ else if (eq != - 1)
+ {
+ String msg
+ = MessageFormat.format(Messages.getString("Parser.NoArg"), //$NON-NLS-1$
+ new Object[] { real.substring(0, eq + index) });
+ throw new OptionException(msg);
+ }
+ found.parsed(argument);
+ }
+
+ private void handleShortOptions(String option) throws OptionException
+ {
+ for (int charIndex = 1; charIndex < option.length(); ++charIndex)
+ {
+ char optChar = option.charAt(charIndex);
+ Option found = null;
+ for (int i = options.size() - 1; i >= 0; --i)
+ {
+ Option opt = (Option) options.get(i);
+ if (optChar == opt.getShortName())
+ {
+ found = opt;
+ break;
+ }
+ }
+ if (found == null)
+ {
+ String msg = MessageFormat.format(Messages.getString("Parser.UnrecDash"), //$NON-NLS-1$
+ new Object[] { "" + optChar }); //$NON-NLS-1$
+ throw new OptionException(msg);
+ }
+ String argument = null;
+ if (found.getTakesArgument())
+ {
+ // If this is a joined short option, and there are more
+ // characters left in this argument, use those as the
+ // argument.
+ if (found.isJoined() && charIndex + 1 < option.length())
+ {
+ argument = option.substring(charIndex + 1);
+ charIndex = option.length();
+ }
+ else
+ argument = getArgument("-" + optChar); //$NON-NLS-1$
+ }
+ found.parsed(argument);
+ }
+ }
+
+ /**
+ * Parse a command line. Any files which are found will be passed to the file
+ * argument callback. This method will exit on error or when --help or
+ * --version is specified.
+ *
+ * @param inArgs the command-line arguments
+ * @param files the file argument callback
+ */
+ public synchronized void parse(String[] inArgs, FileArgumentCallback files)
+ {
+ requireOptions();
+ try
+ {
+ args = inArgs;
+ for (currentIndex = 0; currentIndex < args.length; ++currentIndex)
+ {
+ if (args[currentIndex].length() == 0
+ || args[currentIndex].charAt(0) != '-'
+ || "-".equals(args[currentIndex])) //$NON-NLS-1$
+ {
+ files.notifyFile(args[currentIndex]);
+ continue;
+ }
+ if ("--".equals(args[currentIndex])) //$NON-NLS-1$
+ break;
+ if (args[currentIndex].charAt(1) == '-')
+ handleLongOption(args[currentIndex], 2);
+ else if (longOnly)
+ handleLongOption(args[currentIndex], 1);
+ else
+ handleShortOptions(args[currentIndex]);
+ }
+ // Add remaining arguments to leftovers.
+ for (++currentIndex; currentIndex < args.length; ++currentIndex)
+ files.notifyFile(args[currentIndex]);
+ // See if something went wrong.
+ validate();
+ }
+ catch (OptionException err)
+ {
+ System.err.println(programName + ": " + err.getMessage()); //$NON-NLS-1$
+ String fmt;
+ if (longOnly)
+ fmt = Messages.getString("Parser.TryHelpShort"); //$NON-NLS-1$
+ else
+ fmt = Messages.getString("Parser.TryHelpLong"); //$NON-NLS-1$
+ String msg = MessageFormat.format(fmt, new Object[] { programName });
+ System.err.println(programName + ": " + msg); //$NON-NLS-1$
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Parse a command line. Any files which are found will be returned. This
+ * method will exit on error or when --help or --version is specified.
+ *
+ * @param inArgs the command-line arguments
+ */
+ public String[] parse(String[] inArgs)
+ {
+ final ArrayList fileResult = new ArrayList();
+ parse(inArgs, new FileArgumentCallback()
+ {
+ public void notifyFile(String fileArgument)
+ {
+ fileResult.add(fileArgument);
+ }
+ });
+ return (String[]) fileResult.toArray(new String[0]);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/AbstractTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/AbstractTagImpl.java
new file mode 100644
index 000000000..adb5b65d5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/AbstractTagImpl.java
@@ -0,0 +1,107 @@
+/* gnu.classpath.tools.gjdoc.AbstractTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+
+public abstract class AbstractTagImpl
+ implements Tag, TagContainer {
+
+ private static final Tag[] emptyTags = new Tag[0];
+
+ protected String text;
+ protected Map tagMap;
+
+ protected AbstractTagImpl(String text) {
+ this.text=text;
+ }
+
+ public void resolve() {
+ Tag[] allTags=inlineTags();
+ if (null != allTags) {
+ for (int i=0; i<allTags.length; ++i) {
+ if (allTags[i]!=this) ((AbstractTagImpl)allTags[i]).resolve();
+ }
+ }
+ else {
+ System.err.println("Null tags for " + this);
+ }
+ }
+
+ protected void setBody(String body, ClassDocImpl contextClass, MemberDocImpl contextMember) {
+ this.tagMap=DocImpl.parseCommentTags(body.toCharArray(),
+ 0,
+ body.length(),
+ contextClass,
+ contextMember,
+ this,
+ null);
+ }
+
+ public Tag[] firstSentenceTags() {
+ return (tagMap!=null)? (Tag[])tagMap.get("first") : emptyTags;
+ }
+ public Tag[] inlineTags() {
+ return (tagMap!=null)? (Tag[])tagMap.get("inline") : emptyTags;
+ }
+
+ public String name() {
+ return kind();
+ }
+
+ public String text() {
+ return text;
+ }
+
+ public Map getTagMap() {
+ return tagMap;
+ }
+
+ /**
+ * Debug string containing class, name, text and tagMap.
+ */
+ public String toString()
+ {
+ return (this.getClass().getName()
+ + "[name=" + name()
+ + ", text=" + text()
+ + ", tagMap=" + getTagMap()
+ + "]");
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ArrayCharacterIterator.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ArrayCharacterIterator.java
new file mode 100644
index 000000000..cde5cbe90
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ArrayCharacterIterator.java
@@ -0,0 +1,121 @@
+/* gnu.classpath.tools.gjdoc.ArrayCharacterIterator
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.text.CharacterIterator;
+
+public final class ArrayCharacterIterator implements CharacterIterator {
+
+ private char[] data;
+ private int beginIndex;
+ private int endIndex;
+ private int currentIndex;
+
+ public ArrayCharacterIterator(char[] data,
+ int beginIndex) {
+ this(data,beginIndex,data.length,beginIndex);
+ }
+
+ public ArrayCharacterIterator(char[] data,
+ int beginIndex,
+ int endIndex) {
+ this(data,beginIndex,endIndex,beginIndex);
+ }
+
+ public ArrayCharacterIterator(char[] data,
+ int beginIndex,
+ int endIndex,
+ int currentIndex) {
+ this.data=data;
+ this.beginIndex=beginIndex;
+ this.endIndex=endIndex;
+ this.currentIndex=currentIndex;
+ }
+
+ // Create a copy of this iterator
+ public Object clone() {
+ return new ArrayCharacterIterator(data,beginIndex,endIndex,currentIndex);
+ }
+
+ // Gets the character at the current position (as returned by getIndex()).
+ public char current() {
+ return (currentIndex>=beginIndex && currentIndex<endIndex) ? data[currentIndex] : DONE;
+ }
+
+ // Sets the position to getBeginIndex() and returns the character at that position.
+ public char first() {
+ return data[currentIndex=beginIndex];
+ }
+
+ // Returns the start index of the text.
+ public int getBeginIndex() {
+ return beginIndex;
+ }
+
+ // Returns the end index of the text.
+ public int getEndIndex() {
+ return endIndex;
+ }
+
+ // Returns the current index.
+ public int getIndex() {
+ return currentIndex;
+ }
+
+ // Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty) and returns the character at that position.
+ public char last() {
+ return data[currentIndex=((endIndex>beginIndex)?endIndex-1:endIndex)];
+ }
+
+ // Increments the iterator's index by one and returns the character at the new index.
+ public char next() {
+ return (++currentIndex<endIndex)?data[currentIndex]:DONE;
+ }
+
+ // Decrements the iterator's index by one and returns the character at the new index.
+ public char previous() {
+ return (--currentIndex>=beginIndex)?data[currentIndex]:DONE;
+ }
+
+ // Sets the position to the specified position in the text and returns that character.
+ public char setIndex(int position) {
+ this.currentIndex=position;
+ return current();
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocImpl.java
new file mode 100644
index 000000000..b38c2b083
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocImpl.java
@@ -0,0 +1,1260 @@
+/* gnu.classpath.tools.gjdoc.ClassDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.io.*;
+import gnu.classpath.tools.gjdoc.expr.EvaluatorEnvironment;
+import gnu.classpath.tools.gjdoc.expr.CircularExpressionException;
+import gnu.classpath.tools.gjdoc.expr.IllegalExpressionException;
+import gnu.classpath.tools.gjdoc.expr.UnknownIdentifierException;
+
+public class ClassDocImpl
+ extends ProgramElementDocImpl
+ implements ClassDoc, WritableType, EvaluatorEnvironment {
+
+ private ClassDoc baseClassDoc;
+ private ClassDoc[] importedClasses;
+ private PackageDoc[] importedPackages;
+ private boolean definesSerializableFields;
+ private FieldDoc[] serialPersistentField;
+ private MethodDoc[] serializationMethods;
+ private String dimension = "";
+
+ public ClassDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ int accessLevel,
+ boolean isFinal,
+ boolean isStatic,
+ SourcePosition position) {
+ super(containingClass, containingPackage, accessLevel, isFinal, isStatic,
+ position);
+ this.baseClassDoc = this;
+ }
+
+ public ClassDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ ClassDoc[] importedClasses,
+ PackageDoc[] importedPackages,
+ SourcePosition position) {
+ super(containingClass, containingPackage,
+ position);
+ this.importedClasses=importedClasses;
+ this.importedPackages=importedPackages;
+ this.baseClassDoc = this;
+ }
+
+ // Return constructors in class.
+ public ConstructorDoc[] constructors() {
+ return constructors(true);
+ }
+
+ public ConstructorDoc[] constructors(boolean filter) {
+ return filter ? filteredConstructors : unfilteredConstructors;
+ }
+
+ // Return true if Serializable fields are explicitly defined with the special class member serialPersistentFields.
+ public boolean definesSerializableFields() {
+ return definesSerializableFields;
+ }
+
+ // Return fields in class.
+ public FieldDoc[] fields() {
+ return fields(true);
+ }
+
+ public FieldDoc[] fields(boolean filter) {
+ return filter ? filteredFields : unfilteredFields;
+ }
+
+ private static Set primitiveNames;
+ static {
+ primitiveNames = new HashSet();
+ primitiveNames.add("int");
+ primitiveNames.add("long");
+ primitiveNames.add("char");
+ primitiveNames.add("short");
+ primitiveNames.add("byte");
+ primitiveNames.add("float");
+ primitiveNames.add("double");
+ primitiveNames.add("boolean");
+ }
+
+ private Map findClassCache = new HashMap();
+
+ public ClassDoc findClass(String className, String dimension)
+ {
+ ClassDoc cached = (ClassDoc)findClassCache.get(className + dimension);
+ if (null != cached) {
+ return cached;
+ }
+ else {
+ ClassDoc classDoc = findClass(className);
+
+ if (null!=classDoc) {
+ try {
+ if (classDoc.dimension().equals(dimension)) {
+ return classDoc;
+ }
+ else {
+ ClassDoc rc = (ClassDoc) ((WritableType)classDoc).clone();
+ ((WritableType)rc).setDimension(dimension);
+ findClassCache.put(className + dimension, rc);
+ return rc;
+ }
+ }
+ catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ public ClassDoc findClass(String className)
+ {
+ String qualifiedName = Main.getRootDoc().resolveClassName(className, this);
+ ClassDoc rc=Main.getRootDoc().classNamed(qualifiedName);
+
+ if (null == rc) {
+ for (ClassDoc cdi=this; cdi!=null; cdi=cdi.containingClass()) {
+ for (ClassDoc sdi=cdi; sdi!=null; sdi=sdi.superclass()) {
+ if (sdi instanceof ClassDocProxy) {
+ ClassDoc realClass = Main.getRootDoc().classNamed(sdi.qualifiedName());
+ if (null != realClass) {
+ sdi = realClass;
+ }
+ }
+ rc=Main.getRootDoc().classNamed(sdi.qualifiedName()+"."+className);
+ if (rc!=null) return rc;
+ }
+ }
+ }
+
+ return rc;
+ }
+
+ // Get the list of classes declared as imported.
+ public ClassDoc[] importedClasses() {
+ return importedClasses;
+ }
+
+ // Get the list of packages declared as imported.
+ public PackageDoc[] importedPackages() {
+ return importedPackages;
+ }
+
+ // Return inner classes within this class.
+ public ClassDoc[] innerClasses() {
+ return innerClasses(true);
+ }
+
+ public ClassDoc[] innerClasses(boolean filtered) {
+ return filtered ? filteredInnerClasses : unfilteredInnerClasses;
+ }
+
+ void setFilteredInnerClasses(ClassDoc[] filteredInnerClasses) {
+ this.filteredInnerClasses=filteredInnerClasses;
+ }
+
+ void setInnerClasses(ClassDoc[] unfilteredInnerClasses) {
+ this.unfilteredInnerClasses=unfilteredInnerClasses;
+ }
+
+ // Return interfaces implemented by this class or interfaces extended by this interface.
+ public ClassDoc[] interfaces() {
+ return interfaces;
+ }
+
+ public void setInterfaces(ClassDoc[] interfaces) {
+ this.interfaces=interfaces;
+ }
+
+ // Return true if this class is abstract
+ public boolean isAbstract() {
+ return isAbstract || isInterface();
+ }
+
+ public boolean isInterface() {
+ return isInterface;
+ }
+
+ public boolean isAnnotation() {
+ return isAnnotation;
+ }
+
+ public boolean isEnum()
+ {
+ return isEnum;
+ }
+
+ // Return true if this class is abstract
+ public void setIsAbstract(boolean b) {
+ this.isAbstract=b;
+ }
+
+ // Return true if this class implements java.io.Externalizable.
+ public boolean isExternalizable() {
+ return implementsInterface("java.io.Externalizable");
+ }
+
+ // Return true if this class implements java.io.Serializable.
+ public boolean isSerializable() {
+ return implementsInterface("java.io.Serializable");
+ }
+
+ public boolean implementsInterface(String name) {
+ for (ClassDoc cdi=this; cdi!=null; cdi=(ClassDoc)cdi.superclass()) {
+ if (cdi instanceof ClassDocImpl) {
+ ClassDoc[] cdiInterfaces=(ClassDoc[])cdi.interfaces();
+ if (null != cdiInterfaces) {
+ for (int i=0; i<cdiInterfaces.length; ++i) {
+ if (cdiInterfaces[i].qualifiedName().equals(name))
+ return true;
+ }
+ }
+ }
+ else {
+ //throw new RuntimeException("implementsInterface(\""+name+"\") failed: Not a ClassDocImpl:"+cdi);
+ }
+ }
+ return false;
+ }
+
+ // Return methods in class.
+ public MethodDoc[] methods() {
+ return methods(true);
+ }
+
+ // Return methods in class.
+ public MethodDoc[] methods(boolean filter) {
+ return filter ? filteredMethods : unfilteredMethods;
+ }
+
+ // Return the Serializable fields of class. Return either a list of default fields documented by serial tag or return a single FieldDoc for serialPersistentField member.
+ public FieldDoc[] serializableFields() {
+ if (serialPersistentField!=null) {
+ return serialPersistentField;
+ }
+ else{
+ return serializableFields;
+ }
+ }
+
+ // Return the serialization methods for this class.
+ public MethodDoc[] serializationMethods() {
+ return serializationMethods;
+ }
+
+ // Test whether this class is a subclass of the specified class.
+ public boolean subclassOf(ClassDoc cd) {
+ for (ClassDocImpl cdi=(ClassDocImpl)superclass(); cdi!=null; cdi=(ClassDocImpl)cdi.superclass()) {
+ if (cdi.equals(cd))
+ return true;
+ }
+ return false;
+ }
+
+ // Return the superclass of this class
+ public ClassDoc superclass() {
+ return superclass;
+ }
+
+ // Implementation of Interface Type
+
+ public ClassDoc asClassDoc() {
+
+ return (ClassDoc)this;
+ }
+
+ public String typeName() { return name(); }
+
+ public String qualifiedTypeName() {
+ return (containingPackage()!=null && !containingPackage().equals(PackageDocImpl.DEFAULT_PACKAGE))?(containingPackage().name()+"."+name()):(name());
+ }
+
+ public String qualifiedName() { return qualifiedTypeName(); }
+
+ public String dimension() { return dimension; }
+
+ public String toString() { return "ClassDoc{"+qualifiedTypeName()+"}"; }
+
+ public TypeVariable asTypeVariable() { return null; }
+
+ public static ClassDocImpl createInstance(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ ClassDoc[] importedClasses,
+ PackageDoc[] importedPackages,
+ char[] source, int startIndex, int endIndex,
+ List importStatementList) throws ParseException, IOException {
+
+ String superclassName = "java.lang.Object";
+
+ ClassDocImpl rc=new ClassDocImpl(containingClass,
+ containingPackage,
+ importedClasses,
+ importedPackages,
+ null);
+ rc.setImportStatementList(importStatementList);
+ List implementedInterfaces = new ArrayList();
+
+ String word="";
+ int item=0;
+
+ final int STATE_NORMAL = 1;
+ final int STATE_SLASHC = 2;
+ final int STATE_STARC = 3;
+ final int STATE_ANNO = 4;
+
+ int state=STATE_NORMAL;
+ int varLevel=0;
+ int parLevel=0;
+ char prev=0;
+ for (int ndx=startIndex; ndx<=endIndex; ++ndx) {
+ char c=(ndx==endIndex)?10:source[ndx];
+ boolean processWord=false;
+ if (state==STATE_SLASHC) {
+ if (c=='\n') {
+ state=STATE_NORMAL;
+ c=0;
+ }
+ }
+ else if (state==STATE_STARC) {
+ if (c=='/' && prev=='*') {
+ state=STATE_NORMAL;
+ c=0;
+ }
+ }
+ else {
+ if (c=='/' && prev=='/') {
+ state=STATE_SLASHC;
+ c=0;
+ word=word.substring(0,word.length()-1);
+ processWord=true;
+ }
+ else if (c=='*' && prev=='/') {
+ state=STATE_STARC;
+ c=0;
+ word=word.substring(0,word.length()-1);
+ processWord=true;
+ }
+ else if (c=='@') {
+ state=STATE_ANNO;
+ word += c;
+ }
+ else if (c=='(' && state==STATE_ANNO) {
+ ++parLevel;
+ word += c;
+ }
+ else if (c==')' && state==STATE_ANNO) {
+ --parLevel;
+ word += c;
+ if (parLevel == 0)
+ state=STATE_NORMAL;
+ }
+ else if (c=='<')
+ {
+ ++varLevel;
+ word += c;
+ }
+ else if (c=='>')
+ {
+ --varLevel;
+ word += c;
+ }
+ else if (c=='{' && parLevel == 0 ||
+ c==',' && varLevel == 0 && parLevel == 0 ||
+ Parser.WHITESPACE.indexOf(c)>=0 && parLevel == 0 && varLevel == 0) {
+ processWord=true;
+ state=STATE_NORMAL;
+ }
+ else {
+ word+=c;
+ }
+
+ if (processWord && word.length()>0) {
+ if (item==0) {
+ if (rc.processModifier(word)) {
+ }
+ else if (word.equals("abstract")) {
+ rc.setIsAbstract(true);
+ }
+ else if (word.equals("class")) {
+ rc.setIsInterface(false);
+ item=1;
+ }
+ else if (word.equals("enum"))
+ {
+ rc.setIsEnum(true);
+ item = 1;
+ }
+ else if (word.equals("interface")) {
+ rc.setIsInterface(true);
+ item=1;
+ }
+ else if (word.equals("@interface")) {
+ rc.setIsInterface(true);
+ rc.setIsAnnotation(true);
+ item=1;
+ }
+ else if (word.equals("strictfp")) {
+ }
+ else {
+ Main.getRootDoc().printWarning("unknown modifier '"+word+"'");
+ }
+ }
+ else if (word.equals("extends") && !rc.isAnnotation()) {
+ if (rc.isInterface()) {
+ item=3;
+ }
+ else {
+ item=2;
+ }
+ }
+ else if (word.equals("implements") && !rc.isAnnotation()) {
+ item=3;
+ }
+ else if (item==1) {
+ int parameterIndex = word.indexOf("<");
+ if (parameterIndex == -1)
+ rc.setClass(word);
+ else
+ {
+ rc.setClass(word.substring(0, parameterIndex));
+ parseTypeVariables(rc,word.substring(parameterIndex,
+ word.length()));
+ }
+ }
+ else if (item==2) {
+ //Debug.log(9,"setting baseclass of "+rc+" to "+word);
+ int parameterIndex = word.indexOf("<");
+ if (parameterIndex == -1)
+ superclassName=word;
+ else
+ {
+ /* FIXME: Parse type parameters */
+ superclassName=word.substring(0,parameterIndex);
+ }
+ }
+ else if (item==3) {
+ int parameterIndex = word.indexOf("<");
+ if (parameterIndex == -1)
+ implementedInterfaces.add(word);
+ else
+ {
+ /* FIXME: Parse type parameters */
+ implementedInterfaces.add(word.substring(0,parameterIndex));
+ }
+ }
+ word="";
+ }
+
+ if (c=='{' && state==STATE_NORMAL) break;
+ }
+ prev=c;
+ }
+
+ if (null != containingClass
+ && containingClass.isInterface()) {
+ rc.accessLevel = ACCESS_PUBLIC;
+ }
+
+ if (rc.name()==null) {
+ throw new ParseException("No classdef found in expression \""+new String(source,startIndex,endIndex-startIndex)+"\"");
+ }
+
+ rc.setPosition(ClassDocImpl.getPosition(rc, source, startIndex));
+
+ ClassDoc superclassProxy=new ClassDocProxy(superclassName, rc);
+
+ if (!rc.qualifiedName().equals("java.lang.Object")) {
+ rc.setSuperclass(superclassProxy);
+ }
+
+ ClassDoc[] interfaces=new ClassDoc[implementedInterfaces.size()];
+ for (int i=0; i<interfaces.length; ++i) {
+ interfaces[i]=new ClassDocProxy((String)implementedInterfaces.get(i), rc);
+ }
+ rc.setInterfaces(interfaces);
+
+ if (rc.isInterface() && rc.containingClass()!=null) {
+ rc.setIsStatic(true);
+ }
+ return rc;
+ }
+
+ public void setFields(FieldDoc[] fields) {
+ this.unfilteredFields=fields;
+ }
+
+ public void setFilteredFields(FieldDoc[] fields) {
+ this.filteredFields=fields;
+ }
+
+ public void setSerializableFields(FieldDoc[] sfields) {
+ this.serializableFields=sfields;
+ }
+
+ public void setMethods(MethodDoc[] methods) {
+ this.unfilteredMethods=methods;
+ }
+
+ public void setFilteredMethods(MethodDoc[] methods) {
+ this.filteredMethods=methods;
+ }
+
+ public void setConstructors(ConstructorDoc[] constructors) {
+ this.unfilteredConstructors=constructors;
+ }
+
+ public void setFilteredConstructors(ConstructorDoc[] constructors) {
+ this.filteredConstructors=constructors;
+ }
+
+ // Returns the name of this Doc item.
+ public String name() {
+ if (containingClass==null) {
+ return className;
+ }
+ else {
+ return containingClass.name()+"."+className;
+ }
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClass(String className) {
+ this.className=className;
+ }
+
+ void setSuperclass(ClassDoc superclass) {
+ this.superclass=superclass;
+ }
+
+ public void resolve() throws ParseException {
+ if (!resolved) {
+ resolved=true;
+
+ if (containingClass!=null)
+ ((ClassDocImpl)containingClass).resolve();
+
+ //Debug.log(9,"resolving class '"+qualifiedName()+"'");
+ /*
+ for (int i=0; i<importedPackages.length; ++i) {
+ Debug.log(9,"class "+qualifiedName()+" imports "+importedPackages[i].name());
+ }
+ */
+
+ if (superclass instanceof ClassDocProxy) {
+
+ ClassDoc realClassDoc=findClass(superclass.qualifiedName());
+
+ if (realClassDoc==null) {
+ /*
+ if (true) { // Main.recursiveClasses) {
+ throw new ParseException("In class '"+qualifiedName()+"': class '"+className+"' not found.");
+ }
+ */
+ }
+ else {
+ superclass=realClassDoc;
+ }
+ }
+
+ if (null != interfaces) {
+ for (int i=0; i<interfaces.length; ++i) {
+ if (interfaces[i] instanceof ClassDocProxy) {
+ //Debug.log(9,"class "+qualifiedName()+" implements "+interfaces[i].qualifiedName());
+ ClassDoc realClassDoc=findClass(interfaces[i].qualifiedName());
+ if (realClassDoc==null) {
+ /*
+ if (Main.recursiveClasses) {
+ throw new ParseException("In class '"+qualifiedName()+"': class '"+className+"' not found.");
+ }
+ */
+ }
+ else {
+ //Debug.log(9,"found class '"+className+"': "+interfaces[i]);
+ interfaces[i]=realClassDoc;
+ }
+ }
+ }
+ }
+
+ if (unfilteredFields!=null) {
+ for (int i=0; i<unfilteredFields.length; ++i) {
+ ((FieldDocImpl)unfilteredFields[i]).resolve();
+ if (unfilteredFields[i].name().equals("serialPersistentField")) {
+ serialPersistentField=new FieldDoc[]{unfilteredFields[i]};
+ definesSerializableFields=true;
+ }
+ }
+ }
+
+ if (unfilteredMethods!=null) {
+ for (int i=0; i<unfilteredMethods.length; ++i) {
+ ((MethodDocImpl)unfilteredMethods[i]).resolve();
+ }
+ }
+
+ if (unfilteredConstructors!=null) {
+ for (int i=0; i<unfilteredConstructors.length; ++i) {
+ ((ConstructorDocImpl)unfilteredConstructors[i]).resolve();
+ }
+ }
+
+ List isSerMethodList=new ArrayList();
+
+ if (null != maybeSerMethodList) {
+ for (Iterator it=maybeSerMethodList.iterator(); it.hasNext(); ) {
+ MethodDocImpl method=(MethodDocImpl)it.next();
+ method.resolve();
+
+ if (((method.name().equals("readObject")
+ && method.signature().equals("(java.io.ObjectInputStream)"))
+ || (method.name().equals("writeObject")
+ && method.signature().equals("(java.io.ObjectOutputStream)"))
+ || (method.name().equals("readExternal")
+ && method.signature().equals("(java.io.ObjectInput)"))
+ || (method.name().equals("writeExternal")
+ && method.signature().equals("(java.io.ObjectOutput)"))
+ || (method.name().equals("readResolve")
+ && method.signature().equals("()")))) {
+
+ isSerMethodList.add(method);
+ }
+ }
+ this.serializationMethods=(MethodDoc[])isSerMethodList.toArray(new MethodDoc[0]);
+ maybeSerMethodList=null;
+ }
+ }
+ }
+
+ public FieldDoc findFieldRec(String name) {
+ return findFieldRec(this, name);
+ }
+
+ private static FieldDoc findFieldRec(ClassDoc classDoc, String name)
+ {
+ FieldDoc field = findField(classDoc, name);
+ if (null!=field) {
+ return field;
+ }
+ else {
+ ClassDoc[] interfaces = classDoc.interfaces();
+ for (int i=0; i<interfaces.length; ++i) {
+ field = findFieldRec(interfaces[i], name);
+ if (null != field) {
+ return field;
+ }
+ }
+ if (null != classDoc.superclass()) {
+ return findFieldRec(classDoc.superclass(), name);
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ private static FieldDoc findField(ClassDoc classDoc, String name)
+ {
+ FieldDoc[] fields = classDoc.fields(false);
+ for (int i=0; i<fields.length; ++i) {
+ if (fields[i].name().equals(name)) {
+ return fields[i];
+ }
+ }
+ return null;
+ }
+
+ public FieldDoc findField(String fieldName) {
+ for (int i=0; i<filteredFields.length; ++i) {
+ if (filteredFields[i].name().equals(fieldName)) {
+ return filteredFields[i];
+ }
+ }
+ return null;
+ }
+
+ public void resolveComments() {
+
+ super.resolveComments();
+
+ if (null != unfilteredFields) {
+ for (int i=0; i<unfilteredFields.length; ++i) {
+ ((FieldDocImpl)unfilteredFields[i]).resolveComments();
+ }
+ }
+
+ if (null != serializableFields) {
+ for (int i=0; i<serializableFields.length; ++i) {
+ ((FieldDocImpl)serializableFields[i]).resolveComments();
+ }
+ }
+ if (null != unfilteredMethods) {
+ for (int i=0; i<unfilteredMethods.length; ++i) {
+ ((MethodDocImpl)unfilteredMethods[i]).resolveComments();
+ }
+ }
+ if (null != unfilteredConstructors) {
+ for (int i=0; i<unfilteredConstructors.length; ++i) {
+ ((ConstructorDocImpl)unfilteredConstructors[i]).resolveComments();
+ }
+ }
+
+ resolveTags();
+ }
+
+
+ private String className=null;
+
+ private boolean isAbstract;
+ private boolean isInterface;
+ private boolean isAnnotation;
+ private boolean isEnum;
+ private ClassDoc[] interfaces;
+ private ClassDoc[] filteredInnerClasses;
+ private ClassDoc[] unfilteredInnerClasses;
+ private FieldDoc[] filteredFields;
+ private FieldDoc[] unfilteredFields;
+ private FieldDoc[] serializableFields;
+ private MethodDoc[] filteredMethods;
+ private MethodDoc[] unfilteredMethods;
+ private ConstructorDoc[] filteredConstructors;
+ private ConstructorDoc[] unfilteredConstructors;
+ private TypeVariable[] typeParameters;
+
+ private boolean resolved=false;
+
+ private ClassDoc superclass;
+
+ // Is this Doc item a class.
+ public boolean isClass() {
+ return !isInterface;
+ }
+
+ // return true if this Doc is include in the active set.
+ public boolean isIncluded() {
+ if (this == baseClassDoc) {
+ return isIncluded
+ || (null != containingClass && Main.getInstance().includeAccessLevel(accessLevel));
+ }
+ else {
+ return baseClassDoc.isIncluded();
+ }
+ }
+
+ void setIsIncluded(boolean b) {
+ this.isIncluded=b;
+ }
+
+ private boolean isIncluded=false;
+
+ void setImportedClasses(ClassDoc[] importedClasses) {
+ this.importedClasses=importedClasses;
+ }
+
+ private static Map typeMap = new HashMap();
+
+ Type typeForString(String typeName) throws ParseException {
+ String orgTypename=typeName;
+ int ndx=typeName.indexOf('[');
+ String dim="";
+ if (ndx>=0) {
+ for (int i=ndx; i<typeName.length(); ++i) {
+ if ("[]".indexOf(typeName.charAt(i))>=0) {
+ dim+=typeName.charAt(i);
+ }
+ }
+ typeName=typeName.substring(0,ndx).trim();
+ }
+
+ ClassDoc classDoc = findClass(typeName, dim);
+ if (null != classDoc) {
+ return classDoc;
+ }
+
+ Type type = (Type)typeMap.get(typeName+dim);
+ if (null!=type) {
+ try {
+ if (type.dimension().equals(dim)) {
+ return type;
+ }
+ else {
+ Type rc = (Type) ((WritableType)type).clone();
+ ((WritableType)rc).setDimension(dim);
+ return rc;
+ }
+ }
+ catch (CloneNotSupportedException e) {
+ throw new ParseException(e.toString());
+ }
+ }
+
+ if ("boolean".equals(typeName)
+ || "char".equals(typeName)
+ || "byte".equals(typeName)
+ || "short".equals(typeName)
+ || "int".equals(typeName)
+ || "long".equals(typeName)
+ || "void".equals(typeName)
+ || "float".equals(typeName)
+ || "double".equals(typeName)) {
+ Type rc=new TypeImpl(null, typeName, dim);
+ typeMap.put(typeName+dim, rc);
+ return rc;
+ }
+
+ if (Main.getInstance().isDocletRunning()) {
+ //System.err.println(findClass("java.lang.String"));
+ //throw new ParseException("Doclet running, class not found: "+typeName+" ("+orgTypename+")");
+ }
+ Type rc=new ClassDocProxy(typeName, this);
+ ((WritableType)rc).setDimension(dim);
+ return rc;
+ }
+
+ public boolean isException() {
+ for (ClassDoc cdi=this;
+ cdi!=null;
+ cdi=cdi.superclass()) {
+
+ if ("java.lang.Exception".equals(cdi.qualifiedName()))
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isError() {
+ for (ClassDoc cdi=this; cdi!=null; cdi=cdi.superclass()) {
+ if ("java.lang.Error".equals(cdi.qualifiedName()))
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isOrdinaryClass() {
+ return !isException() && !isError() && !isInterface();
+ }
+
+ public void setIsInterface(boolean b) {
+ this.isInterface=b;
+ }
+
+ public void setIsAnnotation(boolean b) {
+ this.isAnnotation=b;
+ }
+
+ public void setIsEnum(boolean b)
+ {
+ isEnum = b;
+ }
+
+ public ExecutableMemberDoc findExecutableRec(String nameAndSignature) {
+
+ ExecutableMemberDoc rc;
+ for (ClassDoc cdi=this; cdi!=null; ) {
+ rc=findMethod(cdi, nameAndSignature);
+ if (rc!=null) return rc;
+ rc=findConstructor(cdi, nameAndSignature);
+ if (rc!=null) return rc;
+
+ ClassDoc _superclass = cdi.superclass();
+ if (null == _superclass) {
+ break;
+ }
+ else {
+ cdi = _superclass;
+ }
+ }
+ return null;
+ }
+
+ public static ConstructorDoc findConstructor(ClassDoc classDoc, String nameAndSignature) {
+ int ndx=nameAndSignature.indexOf('(');
+ if (ndx<=0)
+ return null;
+ else {
+ String fullSignature = resolveSignature(classDoc, nameAndSignature.substring(ndx));
+ return findConstructor(classDoc,
+ nameAndSignature.substring(0,ndx),
+ fullSignature);
+ }
+ }
+
+ public static ConstructorDoc findConstructor(ClassDoc classDoc, String name, String signature) {
+ ConstructorDoc[] filteredConstructors = classDoc.constructors(true);
+ if (null != filteredConstructors) {
+ for (int i=0; i<filteredConstructors.length; ++i) {
+ ConstructorDoc constructor = filteredConstructors[i];
+ if (constructor.name().equals(name) && constructor.signature().equals(signature))
+ return constructor;
+ }
+ }
+ return null;
+ }
+
+ public static MethodDoc findMethod(ClassDoc classDoc, String nameAndSignature) {
+ int ndx=nameAndSignature.indexOf('(');
+ if (ndx<=0) {
+ return null;
+ }
+ else {
+ String name = nameAndSignature.substring(0,ndx);
+ String fullSignature = resolveSignature(classDoc, nameAndSignature.substring(ndx));
+ return findMethod(classDoc, name, fullSignature);
+ }
+ }
+
+ private static String resolveSignature(ClassDoc classDoc, String signature)
+ {
+ signature = signature.substring(1, signature.length() - 1).trim();
+ if (0 == signature.length()) {
+ return "()";
+ }
+ StringTokenizer st = new StringTokenizer(signature, ",");
+ StringBuffer fullSignature = new StringBuffer("(");
+ while (st.hasMoreTokens()) {
+ String type = st.nextToken().trim();
+ int ndx = type.length();
+ while (ndx > 0 && type.charAt(ndx - 1) == '[' || type.charAt(ndx - 1) == ']') {
+ -- ndx;
+ }
+ String dim = type.substring(ndx);
+ type = type.substring(0, ndx);
+ ClassDoc typeClass = classDoc.findClass(type);
+ if (fullSignature.length() > 1) {
+ fullSignature.append(",");
+ }
+ if (null != typeClass) {
+ fullSignature.append(typeClass.qualifiedName());
+ }
+ else {
+ fullSignature.append(type);
+ }
+ fullSignature.append(dim);
+ }
+ fullSignature.append(')');
+ return fullSignature.toString();
+ }
+
+ public static MethodDoc findMethod(ClassDoc classDoc, String name, String signature) {
+ MethodDoc[] filteredMethods = classDoc.methods(true);
+ if (null != filteredMethods) {
+ for (int i=0; i<filteredMethods.length; ++i) {
+ MethodDoc method = filteredMethods[i];
+ if (method.name().equals(name) && method.signature().equals(signature))
+ return method;
+ }
+ }
+ return null;
+ }
+
+ public boolean equals(Object o) {
+ return (o!=null) && (o instanceof ClassDoc) && ((ClassDoc)o).qualifiedName().equals(qualifiedName());
+ }
+
+ private List maybeSerMethodList;
+
+ void setMaybeSerMethodList(List maybeSerMethodList) {
+ this.maybeSerMethodList=maybeSerMethodList;
+ }
+
+ public void setDimension(String dimension) {
+ this.dimension = dimension;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ ClassDocImpl result = (ClassDocImpl)super.clone();
+ result.baseClassDoc = baseClassDoc;
+ return result;
+ }
+
+ public int superHashCode()
+ {
+ return super.hashCode();
+ }
+
+ public int hashCode()
+ {
+ return qualifiedTypeName().hashCode();
+ }
+
+ public ClassDoc getBaseClassDoc()
+ {
+ return baseClassDoc;
+ }
+
+ public FieldDoc getFieldDoc(String name)
+ {
+ for (int i=0; i<unfilteredFields.length; ++i) {
+ if (name.equals(unfilteredFields[i].name())) {
+ return unfilteredFields[i];
+ }
+ }
+ return null;
+ }
+
+ public MethodDoc getMethodDoc(String name, String signature)
+ {
+ for (int i=0; i<unfilteredMethods.length; ++i) {
+ if (name.equals(unfilteredMethods[i].name())
+ && signature.equals(unfilteredMethods[i].signature())) {
+ return unfilteredMethods[i];
+ }
+ }
+ return null;
+ }
+
+
+ public ConstructorDoc getConstructorDoc(String signature)
+ {
+ for (int i=0; i<unfilteredConstructors.length; ++i) {
+ if (signature.equals(unfilteredConstructors[i].signature())) {
+ return unfilteredConstructors[i];
+ }
+ }
+ return null;
+ }
+
+ private Object findFieldValue(String identifier,
+ ClassDoc classDoc,
+ String fieldName,
+ Set visitedFields)
+ throws UnknownIdentifierException, IllegalExpressionException
+ {
+ while (classDoc != null) {
+ if (classDoc instanceof ClassDocImpl) {
+ FieldDocImpl fieldDoc
+ = (FieldDocImpl)((ClassDocImpl)classDoc).getFieldDoc(fieldName);
+ if (visitedFields.contains(fieldDoc)) {
+ throw new CircularExpressionException("Circular reference detected");
+ }
+ else if (null != fieldDoc) {
+ return fieldDoc.constantValue(visitedFields);
+ }
+ }
+ else {
+ ClassDoc[] _interfaces = classDoc.interfaces();
+ if (null != _interfaces) {
+ for (int i=0; i<_interfaces.length; ++i) {
+ if (_interfaces[i] instanceof ClassDocImpl) {
+ FieldDocImpl fieldDoc
+ = (FieldDocImpl)((ClassDocImpl)_interfaces[i]).getFieldDoc(fieldName);
+ if (visitedFields.contains(fieldDoc)) {
+ throw new CircularExpressionException("Circular reference detected");
+ }
+ else if (null != fieldDoc) {
+ return fieldDoc.constantValue(visitedFields);
+ }
+ }
+ }
+ }
+ }
+ classDoc = classDoc.superclass();
+ }
+ throw new UnknownIdentifierException(identifier);
+ }
+
+ public Object getValue(String identifier, Set visitedFields)
+ throws UnknownIdentifierException, IllegalExpressionException
+ {
+ int ndx = identifier.lastIndexOf('.');
+ if (ndx >= 0) {
+ String _className = identifier.substring(0, ndx);
+ String _fieldName = identifier.substring(ndx + 1);
+
+ ClassDoc _classDoc = findClass(_className);
+ if (null != _classDoc) {
+ return findFieldValue(identifier, _classDoc, _fieldName, visitedFields);
+ }
+ else {
+ throw new UnknownIdentifierException(identifier);
+ }
+ }
+ else {
+ return findFieldValue(identifier, this, identifier, visitedFields);
+ }
+ }
+
+ public boolean isPrimitive()
+ {
+ return false;
+ }
+
+ // Compares this Object with the specified Object for order.
+ public int compareTo(java.lang.Object o) {
+ int rc;
+
+ if (o instanceof ClassDocImpl) {
+
+ ClassDocImpl c1 = this;
+ ClassDocImpl c2 = (ClassDocImpl)o;
+
+ if (null != c1.containingClass() && null == c2.containingClass()) {
+ rc = c1.containingClass().compareTo(c2);
+ if (0 == rc) {
+ rc = 1;
+ }
+ return rc;
+ }
+ else if (null == c1.containingClass() && null != c2.containingClass()) {
+ rc = c1.compareTo(c2.containingClass());
+ if (0 == rc) {
+ rc = -1;
+ }
+ return rc;
+ }
+ else if (null != c1.containingClass() && null != c2.containingClass()) {
+ rc = c1.containingClass().compareTo(c2.containingClass());
+ if (0 != rc) {
+ return rc;
+ }
+ }
+
+ rc = super.compareTo(o);
+ if (0 == rc) {
+ return Main.getInstance().getCollator().compare(containingPackage().name(),
+ ((ClassDocImpl)o).containingPackage().name());
+ }
+ else {
+ return rc;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+
+ private List importStatementList;
+
+ public void setImportStatementList(List importStatementList)
+ {
+ this.importStatementList = new LinkedList();
+ this.importStatementList.addAll(importStatementList);
+ }
+
+ public List getImportSpecifierList()
+ {
+ return importStatementList;
+ }
+
+ public TypeVariable[] typeParameters()
+ {
+ return typeParameters;
+ }
+
+ /**
+ * <p>
+ * Parses the type variables declared in the class definition.
+ * The syntax is:
+ * </p>
+ * <p>
+ * <dl>
+ * <dt>TypeParameters:</dt>
+ * <dd><code>&lt; <em>TypeParameter</em> { <em>, TypeParameter }</code></dd>
+ * <dt>TypeParameter:</dt>
+ * <dd><code><em>Identifier</em> { <strong>extends</strong> <em>Bound</em>
+ * }</dd>
+ * <dt>Bound:</dt>
+ * <dd><code><em>Type</em>{<strong>&</strong> <em>Type</em> } </dd>
+ * </dl>
+ *
+ * @param rc the owning class.
+ * @param typeVariables the string to be parsed.
+ * @throws ParseException if parsing fails.
+ */
+ public static void parseTypeVariables(ClassDocImpl rc,
+ String typeVariables)
+ throws ParseException
+ {
+ List parsedBounds = null;
+ StringTokenizer parameters = new StringTokenizer(typeVariables,
+ Parser.WHITESPACE +
+ "<>,");
+ List variables = new ArrayList();
+ while (parameters.hasMoreTokens())
+ {
+ String parameter = parameters.nextToken();
+ StringTokenizer parts = new StringTokenizer(parameter,
+ Parser.WHITESPACE);
+ TypeVariableImpl variable = new TypeVariableImpl(rc.qualifiedName(),
+ parts.nextToken(),"",
+ rc);
+ if (parts.hasMoreTokens())
+ {
+ if (!parts.nextToken().equals("extends"))
+ throw new ParseException("Invalid type parameter: " + parameter);
+ StringTokenizer bounds = new StringTokenizer(parts.nextToken(),
+ Parser.WHITESPACE
+ + "&");
+ parsedBounds = new ArrayList();
+ while (bounds.hasMoreTokens())
+ {
+ String bound = bounds.nextToken();
+ int nameSep = bound.lastIndexOf(".");
+ String packageName = bound.substring(0, nameSep);
+ String boundName = bound.substring(nameSep, bound.length());
+ parsedBounds.add(new TypeImpl(packageName,boundName,""));
+ }
+ }
+ if (parsedBounds != null)
+ variable.setBounds(parsedBounds);
+ variables.add(variable);
+ }
+ rc.setTypeParameters(variables);
+ }
+
+ /**
+ * Set the type parameters to the contents of the supplied list.
+ *
+ * @param variables a list of type parameters.
+ */
+ void setTypeParameters(List variables)
+ {
+ typeParameters =
+ (TypeVariable[]) variables.toArray(new TypeVariable[variables.size()]);
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocProxy.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocProxy.java
new file mode 100644
index 000000000..253cf5ec4
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocProxy.java
@@ -0,0 +1,169 @@
+/* gnu.classpath.tools.gjdoc.ClassDocProxy
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+
+import java.io.*;
+
+public class ClassDocProxy implements ClassDoc, WritableType {
+
+ private String name;
+ private String qualifiedName;
+ private ClassDoc classContext;
+ private String dimension = "";
+
+ public ClassDocProxy(String qualifiedName, ClassDoc classContext)
+ {
+ this.qualifiedName
+ = Main.getRootDoc().resolveClassName(qualifiedName,
+ (ClassDocImpl)classContext);
+ this.classContext=classContext;
+ int pndx=qualifiedName.lastIndexOf('.');
+ if (pndx>=0) {
+ this.name=qualifiedName.substring(pndx+1);
+ }
+ else {
+ this.name=qualifiedName;
+ }
+ }
+
+ private final String errorText()
+ {
+ return "CLASS "+qualifiedName+" NOT LOADED.";
+ }
+
+ public ConstructorDoc[] constructors() { return new ConstructorDoc[0]; }
+ public ConstructorDoc[] constructors(boolean filtered) { return new ConstructorDoc[0]; }
+ public boolean definesSerializableFields() { return false; }
+ public FieldDoc[] fields() { return new FieldDoc[0]; }
+ public FieldDoc[] fields(boolean filtered) { return new FieldDoc[0]; }
+ public ClassDoc findClass(java.lang.String className) { return null; }
+ public ClassDoc[] importedClasses() { return new ClassDoc[0]; }
+ public PackageDoc[] importedPackages() { return new PackageDoc[0]; }
+ public ClassDoc[] innerClasses() { return new ClassDoc[0]; }
+ public ClassDoc[] innerClasses(boolean filtered) { return new ClassDoc[0]; }
+ public ClassDoc[] interfaces() { return new ClassDoc[0]; }
+ public boolean isAbstract() { return false; }
+ public boolean isExternalizable() { return false; }
+ public boolean isSerializable() { return false; }
+ public MethodDoc[] methods() { return new MethodDoc[0]; }
+ public MethodDoc[] methods(boolean filtered) { return new MethodDoc[0]; }
+ public FieldDoc[] serializableFields() { return new FieldDoc[0]; }
+ public MethodDoc[] serializationMethods() { return new MethodDoc[0]; }
+ public boolean subclassOf(ClassDoc cd) { return false; }
+ public ClassDoc superclass() { return null; }
+ public ClassDoc containingClass() { return null; }
+ public PackageDoc containingPackage() {
+ /*
+ try {
+ File file=Main.getRootDoc().findScheduledClass(qualifiedName, classContext);
+ if (file!=null) {
+ //String clsName=file.getCanonicalFile().getAbsolutePath().substring(new File(Main.getRootDoc().getSourcePath()).getCanonicalFile().getAbsolutePath().length()+1);
+ String clsName=file.getAbsolutePath().substring(new File(Main.getRootDoc().getSourcePath()).getAbsolutePath().length()+1);
+ clsName=clsName.substring(0,clsName.length()-5).replace(File.separatorChar,'.');
+ Debug.log(9,"ClassDocProxy '"+qualifiedName+"': found class "+clsName);
+ qualifiedName=clsName;
+ }
+ return new PackageDocImpl("test.");
+ }
+ catch (Exception e) {
+ return PackageDocImpl.DEFAULT_PACKAGE;
+ }
+ */
+ return PackageDocImpl.DEFAULT_PACKAGE;
+ }
+
+ public boolean isFinal() { return false; }
+ public boolean isPackagePrivate() { return false; }
+ public boolean isPrivate() { return false; }
+ public boolean isProtected() { return false; }
+ public boolean isPublic() { return false; }
+ public boolean isStatic() { return false; }
+ public String modifiers() { return ""; }
+ public int modifierSpecifier() { return 0; }
+ public String qualifiedName() { return qualifiedName; }
+ public String commentText() { return null; }
+ public Tag[] firstSentenceTags() { return new Tag[0]; }
+ public String getRawCommentText() { return null; }
+ public Tag[] inlineTags() { return new Tag[0]; }
+ public boolean isClass() { return false; }
+ public boolean isConstructor() { return false; }
+ public boolean isError() { return false; }
+ public boolean isException() { return false; }
+ public boolean isField() { return false; }
+ public boolean isIncluded() { return false; }
+ public boolean isInterface() { return false; }
+ public boolean isMethod() { return false; }
+ public boolean isOrdinaryClass() { return false; }
+ public String name() { return name; }
+ public SourcePosition position() { return null; }
+ public SeeTag[] seeTags() { return new SeeTag[0]; }
+ public void setRawCommentText(java.lang.String rawDocumentation) {}
+ public Tag[] tags() { return new Tag[0]; }
+ public Tag[] tags(java.lang.String tagname) { return new Tag[0]; }
+ public String typeName() { return name; }
+ public String qualifiedTypeName() { return qualifiedName; }
+ public String dimension() { return dimension; }
+ public ClassDoc asClassDoc() { return this; }
+ public TypeVariable asTypeVariable() { return null; }
+ public boolean isPrimitive() { return false; }
+
+ public String toString() { return "ClassDocProxy{"+qualifiedName+", context="+classContext+"}"; }
+
+ public void setDimension(String dimension) {
+ this.dimension = dimension;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ // Compares this Object with the specified Object for order.
+ public int compareTo(java.lang.Object o) {
+ if (o instanceof Doc) {
+ return Main.getInstance().getCollator().compare(name(), ((Doc)o).name());
+ }
+ else {
+ return 0;
+ }
+ }
+
+ public TypeVariable[] typeParameters() { return new TypeVariable[0]; }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocReflectedImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocReflectedImpl.java
new file mode 100644
index 000000000..9a81cb793
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ClassDocReflectedImpl.java
@@ -0,0 +1,219 @@
+/* gnu.classpath.tools.gjdoc.ClassDocReflectedImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.Map;
+import java.util.HashMap;
+
+public class ClassDocReflectedImpl
+ implements ClassDoc, WritableType
+{
+ private Class clazz;
+ private String name;
+ private ClassDoc superclassDoc;
+ private ClassDoc[] unfilteredInnerClasses;
+ private String dimension = "";
+
+ private static Map reflectionCache = new HashMap();
+
+ public static ClassDocReflectedImpl newInstance(Class clazz)
+ {
+ ClassDocReflectedImpl result
+ = (ClassDocReflectedImpl)reflectionCache.get(clazz);
+ if (null != result) {
+ return result;
+ }
+ else {
+ return new ClassDocReflectedImpl(clazz);
+ }
+ }
+
+ public ClassDocReflectedImpl(Class clazz)
+ {
+ reflectionCache.put(clazz, this);
+
+ //System.err.println("ClassDocReflectedImpl: " + clazz);
+
+ this.clazz = clazz;
+ String className = clazz.getName();
+ int ndx = className.lastIndexOf('.');
+ if (ndx >= 0) {
+ this.name = className.substring(ndx + 1);
+ }
+ else {
+ this.name = className;
+ }
+
+ Class superclass = clazz.getSuperclass();
+ if (null != superclass && !clazz.getName().equals("java.lang.Object")) {
+ this.superclassDoc = (ClassDocReflectedImpl)reflectionCache.get(superclass);
+ if (null == this.superclassDoc) {
+ this.superclassDoc = new ClassDocReflectedImpl(superclass);
+ }
+ }
+
+ Class[] innerclasses = clazz.getDeclaredClasses();
+ this.unfilteredInnerClasses = new ClassDoc[innerclasses.length];
+ for (int i=0; i<innerclasses.length; ++i) {
+ this.unfilteredInnerClasses[i] = (ClassDocReflectedImpl)reflectionCache.get(innerclasses[i]);
+ if (null == this.unfilteredInnerClasses[i]) {
+ this.unfilteredInnerClasses[i] = new ClassDocReflectedImpl(innerclasses[i]);
+ //System.err.println("adding " + this.unfilteredInnerClasses[i] + " [" + innerclasses[i] + "] as inner class of " + this + " [" + clazz + "]");
+ }
+ }
+ }
+
+ public ConstructorDoc[] constructors() { return new ConstructorDoc[0]; }
+ public ConstructorDoc[] constructors(boolean filtered) { return new ConstructorDoc[0]; }
+ public boolean definesSerializableFields() { return false; }
+ public FieldDoc[] fields() { return new FieldDoc[0]; }
+ public FieldDoc[] fields(boolean filtered) { return new FieldDoc[0]; }
+ public ClassDoc findClass(java.lang.String className) { return null; }
+ public ClassDoc[] importedClasses() { return new ClassDoc[0]; }
+ public PackageDoc[] importedPackages() { return new PackageDoc[0]; }
+ public ClassDoc[] innerClasses() { return new ClassDoc[0]; }
+ public ClassDoc[] innerClasses(boolean filtered)
+ {
+ if (filtered) {
+ return new ClassDoc[0];
+ }
+ else {
+ return unfilteredInnerClasses;
+ }
+ }
+
+ public ClassDoc[] interfaces() { return new ClassDoc[0]; }
+ public boolean isAbstract() { return false; }
+ public boolean isExternalizable() { return false; }
+ public boolean isSerializable() { return false; }
+ public MethodDoc[] methods() { return new MethodDoc[0]; }
+ public MethodDoc[] methods(boolean filtered) { return new MethodDoc[0]; }
+ public FieldDoc[] serializableFields() { return new FieldDoc[0]; }
+ public MethodDoc[] serializationMethods() { return new MethodDoc[0]; }
+ public boolean subclassOf(ClassDoc cd) { return false; }
+ public ClassDoc superclass() {
+ return superclassDoc;
+ }
+ public ClassDoc containingClass()
+ {
+ Class declaringClass = clazz.getDeclaringClass();
+ if (null != declaringClass) {
+ return new ClassDocReflectedImpl(declaringClass);
+ }
+ else {
+ return null;
+ }
+ }
+ public PackageDoc containingPackage()
+ {
+ Class outerClass = clazz;
+ while (null != outerClass.getDeclaringClass()) {
+ outerClass = outerClass.getDeclaringClass();
+ }
+
+ String packageName = outerClass.getName();
+ int ndx = packageName.lastIndexOf('.');
+ if (ndx > 0) {
+ packageName = packageName.substring(0, ndx);
+ }
+ else {
+ packageName = "";
+ }
+ PackageDoc result = Main.getRootDoc().findOrCreatePackageDoc(packageName);
+ return result;
+ }
+
+ public boolean isFinal() { return false; }
+ public boolean isPackagePrivate() { return false; }
+ public boolean isPrivate() { return false; }
+ public boolean isProtected() { return false; }
+ public boolean isPublic() { return false; }
+ public boolean isStatic() { return false; }
+ public String modifiers() { return ""; }
+ public int modifierSpecifier() { return 0; }
+ public String qualifiedName() { return clazz.getName().replace('$', '.'); }
+ public String commentText() { return null; }
+ public Tag[] firstSentenceTags() { return new Tag[0]; }
+ public String getRawCommentText() { return null; }
+ public Tag[] inlineTags() { return new Tag[0]; }
+ public boolean isClass() { return false; }
+ public boolean isConstructor() { return false; }
+ public boolean isError() { return false; }
+ public boolean isException() { return false; }
+ public boolean isField() { return false; }
+ public boolean isIncluded() { return false; }
+ public boolean isInterface() { return false; }
+ public boolean isMethod() { return false; }
+ public boolean isOrdinaryClass() { return false; }
+ public String name() { return name; }
+ public SourcePosition position() { return null; }
+ public SeeTag[] seeTags() { return new SeeTag[0]; }
+ public void setRawCommentText(java.lang.String rawDocumentation) {}
+ public Tag[] tags() { return new Tag[0]; }
+ public Tag[] tags(java.lang.String tagname) { return new Tag[0]; }
+ public String typeName() { return name; }
+ public String qualifiedTypeName() { return qualifiedName(); }
+ public ClassDoc asClassDoc() { return this; }
+ public TypeVariable asTypeVariable() { return null; }
+ public boolean isPrimitive() { return false; }
+
+ public String toString() { return "ClassDocReflectedImpl{"+qualifiedName()+"}"; }
+
+ public int compareTo(java.lang.Object o) {
+ if (o instanceof Doc) {
+ return Main.getInstance().getCollator().compare(name(), ((Doc)o).name());
+ }
+ else {
+ return 0;
+ }
+ }
+
+ public String dimension() { return dimension; }
+
+ public void setDimension(String dimension) {
+ this.dimension = dimension;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ public TypeVariable[] typeParameters() { return new TypeVariable[0]; }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ConstructorDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ConstructorDocImpl.java
new file mode 100644
index 000000000..ad31ba69e
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ConstructorDocImpl.java
@@ -0,0 +1,59 @@
+/* gnu.classpath.tools.gjdoc.ConstructorDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.util.*;
+import com.sun.javadoc.*;
+
+public class ConstructorDocImpl extends ExecutableMemberDocImpl implements ConstructorDoc {
+
+ public ConstructorDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ SourcePosition position) {
+
+ super(containingClass,
+ containingPackage,
+ position);
+ }
+
+ // Is this Doc item a constructor.
+ public boolean isConstructor() {
+ return true;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Debug.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Debug.java
new file mode 100644
index 000000000..d5020236c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Debug.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.Debug
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+public final class Debug {
+
+ //private static int logLevel = 7;
+ private static int logLevel = 0;
+
+ static {
+ String llProp = System.getProperty("gnu.classpath.tools.gjdoc.LogLevel");
+ if (null!=llProp) logLevel = Integer.parseInt(llProp);
+ }
+
+ public static final void log(String msg) {
+ System.err.println(msg);
+ }
+
+ public static final void log(int level, String msg) {
+ if (level<=logLevel) {
+ System.err.println(msg);
+ }
+ }
+
+ public static final void dumpArray(int level, Object[] array) {
+ if (level<=logLevel) {
+ for (int i=0; i<array.length; ++i) {
+ System.err.println(" #"+i+": "+array[i]);
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/DirectoryTree.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/DirectoryTree.java
new file mode 100644
index 000000000..706e9b6cc
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/DirectoryTree.java
@@ -0,0 +1,74 @@
+/* gnu.classpath.tools.gjdoc.DirectoryTree
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.io.*;
+
+public class DirectoryTree {
+
+ class FileNode {
+ File file;
+ FileNode[] subNodes;
+
+ FileNode(File file) {
+ this.file=file;
+ if (file.isDirectory()) {
+ File[] subFiles=file.listFiles();
+ subNodes=new FileNode[subFiles.length];
+ for (int i=0; i<subFiles.length; ++i) {
+ subNodes[i]=new FileNode(subFiles[i]);
+ }
+ }
+ }
+ }
+
+ FileNode root;
+
+ DirectoryTree(File path) {
+
+ System.err.print("Scanning "+path.getAbsolutePath()+"... ");
+
+ long now1=System.currentTimeMillis();
+
+ root=new FileNode(path);
+
+ long now2=System.currentTimeMillis();
+
+ System.err.println("took "+(now2-now1)+" ms");
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/DocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/DocImpl.java
new file mode 100644
index 000000000..ecd810040
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/DocImpl.java
@@ -0,0 +1,1090 @@
+/* gnu.classpath.tools.gjdoc.DocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+import java.io.File;
+import javax.swing.text.Segment;
+
+/**
+ * Represents the least common denominator of all Javadoc
+ * comment classes.
+ */
+public abstract class DocImpl implements Doc, TagContainer {
+
+ protected static Tag[] seeTagEmptyArr = new SeeTagImpl[0];
+ protected static Tag[] linkTagEmptyArr = new LinkTagImpl[0];
+ protected static Tag[] paramTagEmptyArr = new ParamTagImpl[0];
+ protected static Tag[] throwsTagEmptyArr = new ThrowsTagImpl[0];
+ protected SourcePosition position;
+ private String boilerplateComment;
+
+ // Return the text of the comment for this doc item.
+ public String commentText() {
+
+ StringBuffer rc=new StringBuffer();
+
+ Tag[] textTags=(Tag[])tagMap.get("text");
+ if (textTags!=null) {
+ for (int i=0; i<textTags.length; ++i) {
+ rc.append(textTags[i].text());
+ }
+ }
+ return rc.toString();
+ }
+
+ // Compares this Object with the specified Object for order.
+ public int compareTo(java.lang.Object o) {
+ return Main.getInstance().getCollator().compare(name(), ((Doc)o).name());
+ }
+
+ // Return the first sentence of the comment as tags.
+ public Tag[] firstSentenceTags() {
+
+ Tag[] rc=(Tag[])tagMap.get("first");
+ if (rc==null) rc=new Tag[0];
+ return rc;
+ }
+
+ // Return the full unprocessed text of the comment.
+ public String getRawCommentText() {
+ if (rawDocumentation!=null)
+ return rawDocumentation;
+ else if (rawDocOffset>=0)
+ return Main.getRootDoc().readRawComment(rawDocOffset);
+ else
+ return null;
+ }
+
+ // Return comment as tags.
+ public Tag[] inlineTags() {
+
+ Tag[] rc=(Tag[])tagMap.get("inline");
+ if (rc==null) rc=new Tag[0];
+ return rc;
+ }
+
+ // Is this Doc item a class.
+ public boolean isClass() {
+ return false;
+ }
+
+ // Is this Doc item a constructor? False until overridden.
+ public boolean isConstructor() {
+ return false;
+ }
+
+ // Is this Doc item a error class? False until overridden.
+ public boolean isError() {
+ return false;
+ }
+
+ // Is this Doc item a exception class? False until overridden.
+ public boolean isException() {
+ return false;
+ }
+
+ // Is this Doc item a field? False until overridden.
+ public boolean isField() {
+ return false;
+ }
+
+ // return true if this Doc is include in the active set.
+ public boolean isIncluded() {
+ return false;
+ }
+
+ // Is this Doc item a interface? False until overridden.
+ public boolean isInterface() {
+ return false;
+ }
+
+ // Is this Doc item a simple method (i.e.
+ public boolean isMethod() {
+ return false;
+ }
+
+ public boolean isPackage() {
+ return false;
+ }
+
+ // Is this Doc item a ordinary class (i.e.
+ public boolean isOrdinaryClass() {
+ return false;
+ }
+
+ // Return the see also tags in this Doc item.
+ public SeeTag[] seeTags() {
+ return (SeeTag[])getTagArr("see", seeTagEmptyArr);
+ }
+
+ protected Tag[] getTagArr(String kindOfTag, Tag[] defaultRc) {
+ Tag[] rc=(Tag[])tagMap.get(kindOfTag);
+ if (rc==null) rc=defaultRc;
+ return rc;
+ }
+
+ // Set the full unprocessed text of the comment.
+ public void setRawCommentText(String rawDocumentation) {
+ this.rawDocumentation=rawDocumentation;
+ }
+
+ public void resolveComments() {
+
+ if (rawDocumentation!=null && tagMap.isEmpty()) {
+ char[] charArray = rawDocumentation.toCharArray();
+ int length = rawDocumentation.length();
+ int startOffset = 0;
+ int endOffset = 0;
+ if (charArray[0] == '/'
+ && charArray[1] == '*'
+ && charArray[2] == '*'
+ && charArray[length - 2] == '*'
+ && charArray[length - 1] == '/') {
+
+ startOffset = 3;
+ endOffset = 2;
+ }
+
+ this.tagMap=parseCommentTags(charArray,
+ startOffset,
+ length - endOffset,
+ getContextClass(),
+ getContextMember(),
+ null,
+ boilerplateComment);
+
+ if (Main.getInstance().isCacheRawComments()) {
+ rawDocOffset=Main.getRootDoc().writeRawComment(rawDocumentation);
+ rawDocumentation=null;
+ }
+
+ resolveTags();
+ }
+ else if (tagMap.isEmpty() && null != boilerplateComment) {
+ tagMap.put("all", new Tag[] { new TagImpl("@boilerplate", boilerplateComment,getContextClass(),null) });
+ tagMap.put("@boilerplate", new Tag[] { new TagImpl("@boilerplate", boilerplateComment,getContextClass(),null) });
+ }
+ }
+
+ public static int skipHtmlWhitespace(char[] buffer, int startIndex) {
+ while (startIndex < buffer.length) {
+ char c=buffer[startIndex];
+ if (!Parser.isWhitespace(c)) {
+ break;
+ }
+ else {
+ ++ startIndex;
+ }
+ }
+ return startIndex;
+ }
+
+ /**
+ * Looks for an end-of-sentence marker in <code>text</code>,
+ * starting at <code>startIndex</code> and stopping at
+ * <code>endIndex</code>.
+ *
+ * @param text the text to be searched
+ * @param startIndex index in <code>text</code> at which to start
+ * @param endIndex index in <code>text</code> at which to stop
+ *
+ * @return the index of the character following the end-of-sentence
+ * marker, <code>endIndex</code> if no end-of-sentence
+ * marker could be found, or -1 if not implemented.
+ */
+ private static int findEndOfSentence(char[] text, int startIndex,
+ int endIndex)
+ {
+ if (Main.getInstance().isUseBreakIterator()) {
+ Segment segment = new Segment(text, startIndex, endIndex - startIndex);
+ BreakIterator breakIterator = BreakIterator.getSentenceInstance(Main.getInstance().getLocale());
+ breakIterator.setText(segment);
+ int result = breakIterator.next();
+ if (BreakIterator.DONE == result) {
+ return endIndex;
+ }
+ else {
+ return result;
+ }
+ }
+ else {
+ while (startIndex < endIndex) {
+ if (text[startIndex] == '.'
+ && (startIndex+1 == endIndex
+ || Character.isWhitespace(text[startIndex+1])
+ || isHTMLBreakTag(text, startIndex+1, endIndex)
+ )) {
+ return startIndex;
+ }
+
+ startIndex++;
+ }
+ return endIndex;
+ }
+ }
+
+ /**
+ * Returns true is the text from start to end begins with a 'p' or 'br' tag.
+ */
+ private static boolean isHTMLBreakTag(char[] text, int start, int end)
+ {
+ String[] breakTags = {
+ "p>", "/p>", "h1>", "h2>", "h3>", "h4>", "h5>", "h6>", "hr>",
+ "pre>", "/pre>"
+ };
+
+ if (text[start] == '<') {
+
+ outer:
+ for (int i=0; i<breakTags.length; ++i) {
+ String tag = breakTags[i];
+ int len = tag.length();
+ if (start + len < end) {
+ for (int j=0; j<len; ++j) {
+ char c = tag.charAt(j);
+ if (Character.toLowerCase(text[start + 1 + j]) != c) {
+ continue outer;
+ }
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ //private static final StringBuffer buf=new StringBuffer(32768);
+ private static final StringBuffer whitespaceBuf=new StringBuffer();
+ private static char[] charBuf = new char[60000];
+ private static int bufPos = 0;
+
+ private static void appendToBuf(char c)
+ {
+ if (bufPos < charBuf.length) {
+ charBuf[bufPos++] = c;
+ }
+ else {
+ //
+ }
+ }
+
+ private static void appendToBuf(StringBuffer s)
+ {
+ if (bufPos + s.length() <= charBuf.length) {
+ s.getChars(0, s.length(), charBuf, bufPos);
+ bufPos += s.length();
+ }
+ else {
+ //
+ }
+ }
+
+ private static void setBufLength(int length)
+ {
+ bufPos = 0;
+ }
+
+ private static String bufToString()
+ {
+ return new String(charBuf, 0, bufPos);
+ }
+
+ private static int bufLength()
+ {
+ return bufPos;
+ }
+
+ public static Map parseCommentTags(char[] comment, int startIndex, int endIndex,
+ ClassDocImpl contextClass, MemberDocImpl contextMember,
+ AbstractTagImpl contextTag, String boilerplateComment) {
+
+ int rawDocStart=skipHtmlWhitespace(comment, startIndex);
+
+ int firstSentenceEnd = 0;
+
+ if (comment.length>rawDocStart) {
+
+ firstSentenceEnd = findEndOfSentence(comment, rawDocStart, comment.length);
+
+ if (firstSentenceEnd < 0) {
+ BreakIterator boundary = BreakIterator.getSentenceInstance(Locale.ENGLISH);
+ boundary.setText(new ArrayCharacterIterator(comment, rawDocStart));
+ boundary.first();
+ boundary.next();
+ firstSentenceEnd = boundary.current();
+ }
+
+ // Always include period at end of sentence if there is one.
+ if (firstSentenceEnd < comment.length
+ && '.' == comment[firstSentenceEnd]) {
+ ++ firstSentenceEnd;
+ }
+ }
+
+ final int STATE_BEGOFLINE = 1;
+ final int STATE_TEXT = 2;
+ final int STATE_PARAM = 3;
+ final int STATE_PARAMVALUE = 4;
+ final int STATE_PARAMWRAP = 5;
+ final int STATE_INLINEPARAM = 6;
+ final int STATE_INLINEPARAMVALUE = 7;
+ final int STATE_WHITESPACE = 8;
+ final int STATE_INLINEPARAMVALUE_BOL = 9;
+ final int STATE_IPV_WHITESPACE = 10;
+
+ int state=STATE_BEGOFLINE;
+ int prevState=STATE_TEXT;
+
+ setBufLength(0);
+ whitespaceBuf.setLength(0);
+
+ String paramName="", paramValue="";
+
+ Map tags=new HashMap();
+ tags.put("inline", new LinkedList());
+ tags.put("first", new LinkedList());
+ tags.put("all", new LinkedList());
+
+ final char EOL=(char)-1;
+
+ for (int i=rawDocStart; i<=endIndex; ++i) {
+ char c=(i<endIndex)?comment[i]:EOL;
+ char peek=(i<endIndex-1)?comment[i+1]:EOL;
+
+ switch (state){
+
+ case STATE_BEGOFLINE:
+ if (i==firstSentenceEnd) {
+ AbstractTagImpl newTag = addTag(tags, "text", bufToString(), true, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ setBufLength(0);
+ }
+
+ if (Parser.isWhitespace(c)) {
+ // ignore
+ }
+ else if (c=='*') {
+ // ignore, but go to STATE_TEXT
+ if (peek!='*' && peek!='@' && peek!=EOL) {
+ state=STATE_WHITESPACE;
+ }
+ }
+ else if (c=='@' || (c=='{' && peek=='@') || c==EOL) {
+ if (bufLength()>0) {
+ addTag(tags, "text", bufToString(), i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ setBufLength(0);
+ }
+ if (c=='{') {
+ ++i;
+ state=STATE_INLINEPARAM;
+ }
+ else {
+ state=STATE_PARAM;
+ }
+ }
+ else {
+ state=STATE_TEXT;
+ appendToBuf(whitespaceBuf);
+ whitespaceBuf.setLength(0);
+ appendToBuf(c);
+ }
+ break;
+
+ case STATE_WHITESPACE:
+ if (i==firstSentenceEnd) {
+ AbstractTagImpl newTag = addTag(tags, "text", bufToString(), true, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ setBufLength(0);
+ }
+
+ if (c=='\n') {
+ whitespaceBuf.append(c);
+ state=STATE_BEGOFLINE;
+ }
+ else if (Parser.isWhitespace(c)) {
+ whitespaceBuf.append(c);
+ }
+ else if (c=='@' || (c=='{' && peek=='@') || c==EOL) {
+ if (bufLength()>0) {
+ AbstractTagImpl newTag = addTag(tags, "text", bufToString(), i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ setBufLength(0);
+ }
+ if (c=='{') {
+ ++i;
+ state=STATE_INLINEPARAM;
+ }
+ else {
+ state=STATE_PARAM;
+ }
+ }
+ else {
+ appendToBuf(whitespaceBuf);
+ whitespaceBuf.setLength(0);
+ appendToBuf(c);
+ state=STATE_TEXT;
+ }
+ break;
+
+ case STATE_PARAMWRAP:
+ if (c=='\n') {
+ appendToBuf(c);
+ }
+ else if (Parser.isWhitespace(c)) {
+ // ignore
+ }
+ else if (c=='*') {
+ // ignore, but go to STATE_TEXT
+ /*
+ if (i<endIndex && comment[i+1]!='*' && comment[i+1]!='@') {
+ state=STATE_PARAMVALUE;
+ }
+ */
+ }
+ else if (c=='@' || c==EOL) {
+ paramValue=bufToString();
+ AbstractTagImpl newTag = addTag(tags, paramName, paramValue, i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ setBufLength(0);
+ if (c=='{') {
+ ++i;
+ state=STATE_INLINEPARAM;
+ }
+ else {
+ state=STATE_PARAM;
+ }
+ }
+ else {
+ state=STATE_PARAMVALUE;
+ appendToBuf(c);
+ }
+ break;
+
+ case STATE_PARAM:
+ if (!(c==EOL || Parser.isWhitespace(c))) {
+ appendToBuf(c);
+ }
+ else if (c=='\n') {
+ paramName=bufToString();
+ setBufLength(0);
+ state=STATE_PARAMWRAP;
+ }
+ else {
+ paramName=bufToString();
+ setBufLength(0);
+ state=STATE_PARAMVALUE;
+ }
+ break;
+
+ case STATE_INLINEPARAM:
+ if (c=='}') {
+ // tag without value
+ paramName=bufToString();
+ AbstractTagImpl newTag = addTag(tags, paramName, "", i<firstSentenceEnd, contextClass, contextMember, contextTag, true);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ state=prevState;
+ setBufLength(0);
+ }
+ else if (!(c==EOL || Parser.isWhitespace(c))) {
+ appendToBuf(c);
+ }
+ else if (c=='\n') {
+ paramName=bufToString();
+ setBufLength(0);
+ state=STATE_INLINEPARAMVALUE_BOL;
+ }
+ else {
+ paramName=bufToString();
+ setBufLength(0);
+ state=STATE_INLINEPARAMVALUE;
+ }
+ break;
+
+ case STATE_PARAMVALUE:
+ if (c==EOL) {
+ paramValue=bufToString();
+ AbstractTagImpl newTag = addTag(tags, paramName, paramValue, i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ }
+ else if (c=='\n') {
+ appendToBuf(c);
+ state=STATE_PARAMWRAP;
+ }
+ else {
+ appendToBuf(c);
+ }
+ break;
+
+ case STATE_INLINEPARAMVALUE:
+ if (c=='\n') {
+ appendToBuf(c);
+ state=STATE_INLINEPARAMVALUE_BOL;
+ }
+ else if (c==EOL || c=='}') {
+ paramValue=bufToString();
+ AbstractTagImpl newTag = addTag(tags, paramName, paramValue, i<firstSentenceEnd, contextClass, contextMember, contextTag, true);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ state=prevState;
+ setBufLength(0);
+ }
+ else {
+ appendToBuf(c);
+ }
+ break;
+
+ case STATE_INLINEPARAMVALUE_BOL:
+ if (Parser.isWhitespace(c)) {
+ // ignore
+ }
+ else if (c=='*') {
+ // ignore, but go to STATE_TEXT
+ if (i<endIndex && peek!='*') {
+ state=STATE_IPV_WHITESPACE;
+ }
+ }
+ else if (c==EOL) {
+ if (bufLength()>0) {
+ AbstractTagImpl newTag = addTag(tags, "text", bufToString(), i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ }
+ }
+ else {
+ state=STATE_INLINEPARAMVALUE;
+ appendToBuf(whitespaceBuf);
+ whitespaceBuf.setLength(0);
+ appendToBuf(c);
+ }
+ break;
+
+ case STATE_IPV_WHITESPACE:
+ if (c=='\n') {
+ whitespaceBuf.append(c);
+ state=STATE_INLINEPARAMVALUE_BOL;
+ }
+ else if (Parser.isWhitespace(c)) {
+ whitespaceBuf.append(c);
+ }
+ else if (c==EOL) {
+ if (bufLength()>0) {
+ AbstractTagImpl newTag = addTag(tags, "text", bufToString(), i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ setBufLength(0);
+ }
+ }
+ else {
+ appendToBuf(whitespaceBuf);
+ whitespaceBuf.setLength(0);
+ appendToBuf(c);
+ state=STATE_INLINEPARAMVALUE;
+ }
+ break;
+
+ case STATE_TEXT:
+ if (i==firstSentenceEnd) {
+ AbstractTagImpl newTag = addTag(tags, "text", bufToString(), true, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ setBufLength(0);
+ }
+
+ if (c==EOL) {
+ paramValue=bufToString();
+ AbstractTagImpl newTag = addTag(tags, "text", paramValue, i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ }
+ else if (c=='\n') {
+ appendToBuf(c);
+ state=STATE_BEGOFLINE;
+ }
+ else if (c=='{' && peek=='@') {
+ paramValue=bufToString();
+ AbstractTagImpl newTag = addTag(tags, "text", paramValue, i<firstSentenceEnd, contextClass, contextMember, contextTag, false);
+ if (null != newTag) {
+ contextTag = newTag;
+ }
+ ++i;
+ setBufLength(0);
+ state=STATE_INLINEPARAM;
+ }
+ else {
+ appendToBuf(c);
+ }
+ break;
+
+ default:
+ throw new Error("illegal state "+state);
+ }
+ }
+
+
+ if (null == contextMember && null != boilerplateComment && Main.getInstance().isCopyLicenseText()) {
+ addTag(tags, "@boilerplate", boilerplateComment, false, contextClass, null, null, false);
+ }
+
+ Map rc=new HashMap();
+
+ for (Iterator it=tags.keySet().iterator(); it.hasNext(); ) {
+ String key=(String)it.next();
+ Tag[] templateArr;
+ List list=(List)tags.get(key);
+
+ if ("see".equals(key))
+ templateArr=new SeeTag[list.size()];
+ else if ("param".equals(key))
+ templateArr=new ParamTag[list.size()];
+ else if ("serialField".equals(key))
+ templateArr=new SerialFieldTag[list.size()];
+ else if ("throws".equals(key) || "exception".equals(key))
+ templateArr=new ThrowsTag[list.size()];
+ else {
+ templateArr=new Tag[list.size()];
+ }
+
+ rc.put(key, list.toArray(templateArr));
+ }
+
+ return rc;
+ }
+
+ private ClassDocImpl getContextClass() {
+ if (isClass() || isInterface()) {
+ return (ClassDocImpl)this;
+ }
+ else if (isField() || isMethod() || isConstructor()) {
+ return (ClassDocImpl)((MemberDocImpl)this).containingClass();
+ }
+ else {
+ return null;
+ }
+ }
+
+ private MemberDocImpl getContextMember() {
+ if (isField() || isMethod() || isConstructor()) {
+ return (MemberDocImpl)this;
+ }
+ else {
+ return null;
+ }
+ }
+
+ protected static AbstractTagImpl addTag(Map tags, String name,
+ String value, boolean isFirstSentence,
+ ClassDocImpl contextClass,
+ MemberDocImpl contextMember,
+ AbstractTagImpl contextTag,
+ boolean isInline) {
+
+ AbstractTagImpl tag = null;
+
+ boolean haveValue = (0 != value.trim().length());
+
+ String emptyWarning = "Empty @" + name + " tag.";
+
+ if (name.equals("param")) {
+ if (haveValue) {
+ tag=new ParamTagImpl(value, contextClass, contextMember);
+ }
+ else {
+ //printWarning(emptyWarning);
+ }
+ }
+ else if (name.equals("see")) {
+ if (haveValue) {
+ tag=new SeeTagImpl(value, contextClass);
+ }
+ else {
+ //printWarning(emptyWarning);
+ }
+ }
+ else if (name.equals("link") || name.equals("linkplain")) {
+ if (haveValue) {
+ tag=new LinkTagImpl("@" + name, value, contextClass);
+ isInline = true;
+ }
+ else {
+ //printWarning(emptyWarning);
+ }
+ }
+ else if (name.equals("value")) {
+ if (haveValue) {
+ tag=new ValueTagImpl(value, contextClass);
+ isInline = true;
+ }
+ else {
+ //printWarning(emptyWarning);
+ }
+ }
+ else if (name.equals("inheritDoc")) {
+ if (haveValue) {
+ //printWarning("@inheritDoc tags are not supposed to have any content.");
+ }
+ tag=new InheritDocTagImpl(contextClass, contextMember, contextTag);
+ isInline = true;
+ }
+ else if (name.equals("serialField")) {
+ if (haveValue) {
+ tag=new SerialFieldTagImpl(value, contextClass, contextMember);
+ }
+ else {
+ //printWarning(emptyWarning);
+ }
+ }
+ else if (name.equals("throws") || name.equals("exception")) {
+ if (haveValue) {
+ tag=new ThrowsTagImpl(value, contextClass, contextMember);
+ }
+ else {
+ //printWarning(emptyWarning);
+ }
+ name="throws";
+ }
+ else if (name.equals("text")) {
+ tag=new TextTagImpl(value);
+ isInline = true;
+ }
+ else {
+ tag=new TagImpl("@"+name, value.trim(), contextClass, contextMember);
+ // FIXME: consider taglets
+ }
+
+ if (tag != null) {
+ if (isInline) {
+ ((List)tags.get("inline")).add(tag);
+ if (isFirstSentence) {
+ if (name.equals("text")) {
+ String txt = ((TextTagImpl)tag).getText();
+ Tag newTag;
+ if (txt.startsWith("<p>")) {
+ newTag = new TextTagImpl(txt.substring(3));
+ }
+ else if (txt.endsWith("</p>")) {
+ newTag = new TextTagImpl(txt.substring(0, txt.length() - 4));
+ }
+ else {
+ newTag = tag;
+ }
+ ((List)tags.get("first")).add(newTag);
+
+ }
+ else {
+ ((List)tags.get("first")).add(tag);
+ }
+ }
+ }
+ else {
+ ((List)tags.get("all")).add(tag);
+ }
+
+ List l=((List)tags.get(name));
+ if (l==null) {
+ l=new LinkedList();
+ tags.put(name,l);
+ }
+ l.add(tag);
+
+ return isInline ? tag : contextTag;
+ }
+ else {
+ return null;
+ }
+ }
+
+ // Return all tags in this Doc item.
+ public Tag[] tags() {
+ Tag[] rc=(Tag[])tagMap.get("all");
+ if (rc==null) rc=new Tag[0];
+ return rc;
+ }
+
+ // Return tags of the specified kind in this Doc item.
+ public Tag[] tags(java.lang.String tagname) {
+ Tag[] rc=(Tag[])tagMap.get(tagname);
+ if (rc==null) rc=new Tag[0];
+ return rc;
+ }
+
+ protected String rawDocumentation;
+ protected long rawDocOffset=-1;
+
+ protected Map tagMap = new HashMap();
+
+ public Map getTagMap() { return tagMap; }
+
+ protected void resolveTags() {
+
+ Tag[] tags=tags();
+ for (int i=0; i<tags.length; ++i) {
+ ((AbstractTagImpl)tags[i]).resolve();
+ }
+
+ Tag[] inlineTags=inlineTags();
+ for (int i=0; i<inlineTags.length; ++i) {
+ ((AbstractTagImpl)inlineTags[i]).resolve();
+ }
+ }
+
+ private static Map classDocToFileMap = new HashMap();
+
+ private static File getFile(ClassDoc classDoc) {
+ File result = (File)classDocToFileMap.get(classDoc);
+ if (null == result) {
+ result = new File(((GjdocPackageDoc)classDoc.containingPackage()).packageDirectory(),
+ classDoc.name() + ".java");
+ classDocToFileMap.put(classDoc, result);
+ }
+ return result;
+ }
+
+ public static SourcePosition getPosition(ClassDoc classDoc)
+ {
+ return new SourcePositionImpl(getFile(classDoc), 0, 0);
+ }
+
+ public static SourcePosition getPosition(ClassDoc classDoc, char[] source, int startIndex)
+ {
+ int column = 0;
+ int line = 0;
+ for (int i=0; i<startIndex; ++i) {
+ if (10 == source[i]) {
+ ++ line;
+ column = 0;
+ }
+ else if (13 != source[i]) {
+ ++ column;
+ }
+ }
+ while (true) {
+ ClassDoc containingClassDoc = classDoc.containingClass();
+ if (null != containingClassDoc) {
+ classDoc = containingClassDoc;
+ }
+ else {
+ break;
+ }
+ }
+
+ File file = getFile(classDoc);
+
+ return new SourcePositionImpl(file, line + 1, column + 1);
+ }
+
+ public SourcePosition position()
+ {
+ return this.position;
+ }
+
+ public DocImpl(SourcePosition position)
+ {
+ this.position = position;
+ }
+
+ public void setPosition(SourcePosition position)
+ {
+ this.position = position;
+ }
+
+ private static TagContainer checkForInheritedDoc(ClassDoc classDoc,
+ MemberDocImpl memberDoc,
+ AbstractTagImpl tag)
+ {
+ DocImpl result;
+
+ if (!(classDoc instanceof ClassDocImpl)) {
+ result = null;
+ }
+ else if (null == memberDoc) {
+ result = (DocImpl)classDoc;
+ }
+ else if (memberDoc.isField()) {
+ result = (DocImpl)((ClassDocImpl)classDoc).getFieldDoc(memberDoc.name());
+ }
+ else if (memberDoc.isMethod()) {
+ result = (DocImpl)((ClassDocImpl)classDoc).getMethodDoc(memberDoc.name(),
+ ((MethodDoc)memberDoc).signature());
+ }
+ else if (memberDoc.isConstructor()) {
+ result = (DocImpl)((ClassDocImpl)classDoc).getConstructorDoc(((ConstructorDoc)memberDoc).signature());
+ }
+ else {
+ //assert(false);
+ throw new RuntimeException("memberDoc is supposed to be field, method or constructor");
+ }
+
+ if (null != result
+ && null != memberDoc
+ && null != tag) {
+
+ TagContainer tagDoc = null;
+
+ Tag[] tags = result.tags();
+ for (int i=0; i<tags.length; ++i) {
+ if (tags[i].kind().equals(tag.kind())) {
+ if ("@param".equals(tag.kind())) {
+ if (((ParamTagImpl)tags[i]).parameterName().equals(((ParamTagImpl)tag).parameterName())) {
+ tagDoc = (TagContainer)tags[i];
+ break;
+ }
+ }
+ else if ("@throws".equals(tag.kind())) {
+ if (((ThrowsTagImpl)tags[i]).exceptionName().equals(((ThrowsTagImpl)tag).exceptionName())) {
+ tagDoc = (TagContainer)tags[i];
+ break;
+ }
+ }
+ else if ("@return".equals(tag.kind())) {
+ tagDoc = (TagContainer)tags[i];
+ }
+ }
+ }
+
+ return tagDoc;
+ }
+
+ if (null == result || result.isEmptyDoc()) {
+ return null;
+ }
+ else {
+ return result;
+ }
+ }
+
+ public static TagContainer findInheritedDoc(ClassDoc classDoc,
+ MemberDocImpl memberDoc,
+ AbstractTagImpl tag)
+ {
+ TagContainer result;
+
+ // (Taken from Javadoc Solaris Tool documentation 1.5,
+ // section "Automatic Copying of Method Comments")
+
+ // Algorithm for Inheriting Method Comments - If a method does
+ // not have a doc comment, or has an {@inheritDoc} tag, the
+ // Javadoc tool searches for an applicable comment using the
+ // following algorithm, which is designed to find the most
+ // specific applicable doc comment, giving preference to
+ // interfaces over superclasses:
+
+ // 1. Look in each directly implemented (or extended) interface
+ // in the order they appear following the word implements (or
+ // extends) in the method declaration. Use the first doc comment
+ // found for this method.
+
+ ClassDoc[] interfaces = classDoc.interfaces();
+ if (null != interfaces) {
+ for (int i=0; i<interfaces.length; ++i) {
+ result = checkForInheritedDoc(interfaces[i], memberDoc, tag);
+ if (null != result) {
+ return result;
+ }
+ }
+ }
+
+ // 2. If step 1 failed to find a doc comment, recursively apply
+ // this entire algorithm to each directly implemented (or
+ // extended) interface, in the same order they were examined
+ // in step 1.
+
+ if (null != interfaces) {
+ for (int i=0; i<interfaces.length; ++i) {
+ result = findInheritedDoc(interfaces[i], memberDoc, tag);
+ if (null != result) {
+ return result;
+ }
+ }
+ }
+
+ ClassDoc superclassDoc = classDoc.superclass();
+
+ // 3. If step 2 failed to find a doc comment and this is a class
+ // other than Object (not an interface):
+ if (!classDoc.isInterface()
+ && null != superclassDoc
+ && !"java.lang.Object".equals(classDoc.qualifiedTypeName())) {
+
+ // 3a. If the superclass has a doc comment for this method, use it.
+
+ result = checkForInheritedDoc(superclassDoc, memberDoc, tag);
+ if (null != result) {
+ return result;
+ }
+
+ // 3b. If step 3a failed to find a doc comment, recursively
+ // apply this entire algorithm to the superclass.
+
+ return findInheritedDoc(superclassDoc,
+ memberDoc, tag);
+ }
+ else {
+ return null;
+ }
+ }
+
+ public boolean isEmptyDoc()
+ {
+ return tagMap.isEmpty();
+ }
+
+ void setBoilerplateComment(String boilerplateComment)
+ {
+ this.boilerplateComment = boilerplateComment;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ErrorReporter.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ErrorReporter.java
new file mode 100644
index 000000000..3c139ab25
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ErrorReporter.java
@@ -0,0 +1,121 @@
+/* gnu.classpath.tools.gjdoc.ErrorReporter
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.*;
+
+/**
+ * Simple implementation of a <code>DocErrorReporter</code>: writes
+ * to <code>System.err</code>.
+ */
+public class ErrorReporter implements DocErrorReporter {
+
+ private PrintStream out;
+
+ /**
+ * Keeps track of the number of errors occured
+ * during generation.
+ */
+ private int errorCount=0;
+
+ /**
+ * Keeps track of the number of warnings occured
+ * during generation.
+ */
+ private int warningCount=0;
+
+ /*
+ * When <code>true</code>, no notices will be emitted.
+ */
+ private boolean quiet = false;
+
+ /*
+ * When <code>true</code>, no warnings will be emitted.
+ */
+ private boolean noWarn = false;
+
+ public ErrorReporter()
+ {
+ this.out = System.err;
+ }
+
+ // Print error message, increment error count.
+ public void printError(java.lang.String msg) {
+ out.println("ERROR: "+msg);
+ ++errorCount;
+ }
+
+ // Print error message, increment error count.
+ public void printFatal(java.lang.String msg) {
+ out.println("FATAL: "+msg);
+ System.exit(10);
+ }
+
+ // Print a message.
+ public void printNotice(java.lang.String msg) {
+ if (!quiet) {
+ out.println(msg);
+ }
+ }
+
+ // Print warning message, increment warning count.
+ public void printWarning(java.lang.String msg) {
+ if (!noWarn) {
+ out.println("WARNING: "+msg);
+ ++warningCount;;
+ }
+ }
+
+ public int getErrorCount() {
+ return errorCount;
+ }
+
+ public int getWarningCount() {
+ return warningCount;
+ }
+
+ /**
+ * Specify whether notices should be printed.
+ */
+ public void setQuiet(boolean quiet) {
+ this.quiet = quiet;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ExecutableMemberDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ExecutableMemberDocImpl.java
new file mode 100644
index 000000000..d5b1b1eb0
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ExecutableMemberDocImpl.java
@@ -0,0 +1,427 @@
+/* gnu.classpath.tools.gjdoc.ExecutableMemberDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.util.*;
+import java.io.*;
+import com.sun.javadoc.*;
+
+public class ExecutableMemberDocImpl extends MemberDocImpl implements ExecutableMemberDoc {
+
+ protected ExecutableMemberDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ SourcePosition position) {
+
+ super(containingClass,
+ containingPackage,
+ position);
+ }
+
+ protected boolean processModifier(String word) {
+ if (super.processModifier(word)) {
+ return true;
+ }
+ else if (word.equals("synchronized")) {
+ isSynchronized=true;
+ return true;
+ }
+ else if (word.equals("native")) {
+ isNative=true;
+ return true;
+ }
+ else if (word.equals("abstract")) {
+ isAbstract=true;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ private boolean isAbstract=false;
+ private boolean isNative=false;
+ private boolean isSynchronized=false;
+
+ public boolean isAbstract() { return isAbstract; }
+
+ public boolean isNative() { return isNative; }
+
+ public boolean isSynchronized() { return isSynchronized; }
+
+ public ClassDoc[] thrownExceptions() { return thrownExceptions; }
+
+ public Parameter[] parameters() { return parameters; }
+
+ public ThrowsTag[] throwsTags() {
+ return (ThrowsTag[])getTagArr("throws", throwsTagEmptyArr);
+ }
+
+ public ParamTag[] paramTags() {
+ return (ParamTag[])getTagArr("param", paramTagEmptyArr);
+ }
+
+ public String signature() { return signature; }
+ public String flatSignature() { return flatSignature; }
+
+ public ClassDoc overriddenClass() {
+ for (ClassDoc cdi=(ClassDoc)containingClass().superclass(); cdi!=null; cdi=(ClassDoc)cdi.superclass()) {
+ if (null!=ClassDocImpl.findMethod(cdi, name(), signature()))
+ return cdi;
+ }
+ return null;
+ }
+
+ public static ExecutableMemberDocImpl createFromSource(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ char[] source, int startIndex, int endIndex) throws IOException, ParseException {
+
+ int lastchar=32;
+ StringBuffer methodName=new StringBuffer();
+ for (int i=startIndex; i<endIndex && source[i]!='('; ++i) {
+ if ((Parser.WHITESPACE.indexOf(lastchar)>=0 && Parser.WHITESPACE.indexOf(source[i])<0)
+ || (lastchar == ']' && Parser.WHITESPACE.indexOf(source[i])<0 && '[' != source[i])) {
+ methodName.setLength(0);
+ methodName.append(source[i]);
+ }
+ else if (Parser.WHITESPACE.indexOf(source[i])<0) {
+ methodName.append(source[i]);
+ }
+ lastchar=source[i];
+ }
+
+ ExecutableMemberDocImpl rc;
+
+ SourcePosition position = DocImpl.getPosition(containingClass, source, startIndex);
+
+ if (methodName.toString().equals(((ClassDocImpl)containingClass).getClassName())) {
+
+ // Constructor
+
+ rc=new ConstructorDocImpl(containingClass,
+ containingPackage,
+ position);
+ }
+ else {
+
+ // Normal method
+
+ rc=new MethodDocImpl(containingClass,
+ containingPackage,
+ position);
+ }
+
+ if (containingClass.isInterface())
+ rc.accessLevel=ACCESS_PUBLIC;
+
+ int ndx=rc.parseModifiers(source, startIndex, endIndex);
+ StringBuffer name = new StringBuffer();
+
+ final int STATE_NORMAL=1;
+ final int STATE_STARC=2;
+ final int STATE_SLASHC=3;
+
+ int state=STATE_NORMAL;
+
+ while (source[ndx]!='(' && ndx<endIndex) {
+ if (state==STATE_NORMAL) {
+ if (ndx<endIndex-1 && source[ndx]=='/' && source[ndx+1]=='/') {
+ ++ndx;
+ state=STATE_SLASHC;
+ }
+ else if (ndx<endIndex-1 && source[ndx]=='/' && source[ndx+1]=='*') {
+ ++ndx;
+ state=STATE_STARC;
+ }
+ else {
+ name.append(source[ndx]);
+ }
+ }
+ else if (state==STATE_SLASHC) {
+ if (source[ndx]=='\n')
+ state=STATE_NORMAL;
+ }
+ else if (state==STATE_STARC) {
+ if (ndx<endIndex-1 && source[ndx]=='*' && source[ndx+1]=='/') {
+ ++ndx;
+ state=STATE_NORMAL;
+ }
+ }
+ ++ndx;
+ }
+ rc.setName(name.toString().trim());
+
+ state=STATE_NORMAL;
+
+ ++ndx;
+ int endx;
+ String param="";
+ List parameterList=new ArrayList();
+ for (endx=ndx; endx<endIndex; ++endx) {
+ if (state==STATE_SLASHC) {
+ if (source[endx]=='\n') {
+ state=STATE_NORMAL;
+ }
+ }
+ else if (state==STATE_STARC) {
+ if (source[endx]=='*' && source[endx+1]=='/') {
+ state=STATE_NORMAL;
+ ++endx;
+ }
+ }
+ else if (source[endx]=='/' && source[endx+1]=='*') {
+ state=STATE_STARC;
+ ++endx;
+ }
+ else if (source[endx]=='/' && source[endx+1]=='/') {
+ state=STATE_SLASHC;
+ ++endx;
+ }
+ else if (source[endx]==',' || source[endx]==')') {
+ param=param.trim();
+ if (param.length()>0) {
+ int n = param.length()-1;
+ int paramNameStart = 0;
+ while (n >= 0) {
+ char c = param.charAt(n);
+ if ('[' == c || ']' == c || Parser.WHITESPACE.indexOf(c)>=0) {
+ paramNameStart = n + 1;
+ break;
+ }
+ else {
+ -- n;
+ }
+ }
+ while (n >= 0 && ('[' == param.charAt(n)
+ || ']' == param.charAt(n)
+ || Parser.WHITESPACE.indexOf(param.charAt(n))>=0)) {
+ -- n;
+ }
+ int paramTypeEnd = n + 1;
+ int paramTypeStart = 0;
+ while (n >= 0) {
+ char c = param.charAt(n);
+ if ('[' == c || ']' == c || Parser.WHITESPACE.indexOf(c)>=0) {
+ paramTypeStart = n + 1;
+ break;
+ }
+ else {
+ -- n;
+ }
+ }
+
+ String paramType;
+ String paramName;
+ if (0 != paramNameStart) {
+ paramType=param.substring(paramTypeStart, paramTypeEnd);
+ paramName=param.substring(paramNameStart);
+ }
+ else {
+ paramName = "";
+ StringBuffer paramTypeBuffer = new StringBuffer();
+ for (int i=0; i<param.length(); ++i) {
+ char c = param.charAt(i);
+ if ('[' != c && ']' != c && Parser.WHITESPACE.indexOf(c)<0) {
+ paramTypeBuffer.append(c);
+ }
+ }
+ paramType = paramTypeBuffer.toString();
+ }
+ String dimSuffix="";
+
+ for (int i=0; i<param.length(); ++i) {
+ if ('[' == param.charAt(i)) {
+ dimSuffix += "[]";
+ }
+ }
+ paramType+=dimSuffix;
+
+ if (paramType.startsWith("[")) {
+ System.err.println("broken param type in " + rc + " in " +containingClass);
+ }
+
+ parameterList.add(new ParameterImpl(paramName, paramType,
+ ((ClassDocImpl)containingClass).typeForString(paramType)));
+
+ param="";
+ }
+ }
+ else
+ param+=source[endx];
+
+ if (source[endx]==')' && state==STATE_NORMAL)
+ break;
+ }
+
+ rc.setParameters((Parameter[])parameterList.toArray(new Parameter[0]));
+
+ ++endx;
+ String word="";
+ String dimSuffix="";
+ boolean haveThrowsKeyword=false;
+ List thrownExceptionsList=new ArrayList();
+
+ state=STATE_NORMAL;
+ for (; endx<endIndex; ++endx) {
+ if (state==STATE_SLASHC) {
+ if (source[endx]=='\n') state=STATE_NORMAL;
+ }
+ else if (state==STATE_STARC) {
+ if (source[endx]=='*' && source[endx+1]=='/') {
+ state=STATE_NORMAL;
+ ++endx;
+ }
+ }
+ else if (source[endx]=='/' && source[endx+1]=='*') {
+ state=STATE_STARC;
+ ++endx;
+ }
+ else if (source[endx]=='/' && source[endx+1]=='/') {
+ state=STATE_SLASHC;
+ ++endx;
+ }
+ else if (Parser.WHITESPACE.indexOf(source[endx])>=0) {
+ word=word.trim();
+ if (!haveThrowsKeyword && word.length()>0) {
+ if (word.equals("throws")) haveThrowsKeyword=true;
+ else System.err.println("ARGH! "+word);
+ word="";
+ }
+ }
+ else if (source[endx]=='[' || source[endx]==']') {
+ dimSuffix += source[endx];
+ }
+ else if (source[endx]==',' || source[endx]=='{' || source[endx]==';') {
+ word=word.trim();
+ if (word.length()>0) {
+ ClassDoc exceptionType=rc.containingClass().findClass(word);
+ if (exceptionType==null) {
+ exceptionType=new ClassDocProxy(word,
+ rc.containingClass());
+ }
+ thrownExceptionsList.add(exceptionType);
+ }
+ if (source[endx]=='{') {
+ break;
+ }
+ else {
+ word="";
+ }
+ }
+ else {
+ word+=source[endx];
+ }
+ }
+
+ if (dimSuffix.length()>0) {
+ rc.setTypeName(rc.getTypeName()+dimSuffix);
+ }
+
+ rc.setThrownExceptions((ClassDoc[])thrownExceptionsList.toArray(new ClassDoc[0]));
+
+ return rc;
+ }
+
+ private ClassDoc[] thrownExceptions;
+ private Parameter[] parameters;
+ private String signature;
+ private String flatSignature;
+
+ void setParameters(Parameter[] parameters) {
+ this.parameters=parameters;
+ }
+
+ void setThrownExceptions(ClassDoc[] thrownExceptions) {
+ this.thrownExceptions=thrownExceptions;
+ }
+
+ void resolve() {
+
+ for (int i=0; i<thrownExceptions.length; ++i) {
+ if (thrownExceptions[i] instanceof ClassDocProxy) {
+ String className=thrownExceptions[i].qualifiedName();
+ ClassDoc realClassDoc=containingClass().findClass(className);
+ if (realClassDoc!=null)
+ thrownExceptions[i]=realClassDoc;
+ }
+ }
+
+ StringBuffer signatureBuf=new StringBuffer();
+ StringBuffer flatSignatureBuf=new StringBuffer();
+
+ for (int i=0; i<parameters.length; ++i) {
+ ((ParameterImpl)parameters[i]).resolve(containingClass());
+
+ if (signatureBuf.length()>0) {
+ signatureBuf.append(",");
+ flatSignatureBuf.append(",");
+ }
+ signatureBuf.append(parameters[i].type().qualifiedTypeName());
+ flatSignatureBuf.append(parameters[i].type().typeName());
+ signatureBuf.append(parameters[i].type().dimension());
+ flatSignatureBuf.append(parameters[i].type().dimension());
+ }
+ this.signature="("+signatureBuf.toString()+")";
+ this.flatSignature="("+flatSignatureBuf.toString()+")";
+
+ super.resolve();
+
+ }
+
+ public int compareTo(Object other) {
+ int rc;
+ if (other instanceof MemberDocImpl) {
+ MemberDocImpl otherMember = (MemberDocImpl)other;
+ rc = name().compareTo(otherMember.name());
+ if (0 == rc) {
+ if (other instanceof ExecutableMemberDocImpl) {
+ rc = signature().compareTo(((ExecutableMemberDocImpl)other).signature());
+ if (0 == rc) {
+ return containingClass().compareTo(otherMember.containingClass());
+ }
+ }
+ else {
+ rc = 1;
+ }
+ }
+ }
+ else {
+ rc = 1;
+ }
+ return rc;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/FieldDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/FieldDocImpl.java
new file mode 100644
index 000000000..f99024daa
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/FieldDocImpl.java
@@ -0,0 +1,409 @@
+/* gnu.classpath.tools.gjdoc.FieldDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.util.*;
+import com.sun.javadoc.*;
+import java.lang.reflect.Modifier;
+
+import gnu.classpath.tools.gjdoc.expr.Evaluator;
+import gnu.classpath.tools.gjdoc.expr.CircularExpressionException;
+import gnu.classpath.tools.gjdoc.expr.IllegalExpressionException;
+
+public class FieldDocImpl
+ extends MemberDocImpl
+ implements FieldDoc, Cloneable
+{
+
+ private boolean isTransient;
+ private boolean isVolatile;
+ private String valueLiteral;
+ private Object constantValue;
+ private boolean constantValueEvaluated;
+
+ private FieldDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ SourcePosition position) {
+
+ super(containingClass,
+ containingPackage,
+ position);
+ }
+
+ private static FieldDocImpl createFieldDoc(FieldDocImpl prototype,
+ String fieldDef,
+ String fieldValueLiteral)
+ {
+ if (null != fieldValueLiteral && fieldValueLiteral.length() == 0) {
+ fieldValueLiteral = null;
+ }
+
+ try {
+ FieldDocImpl fieldDoc=(FieldDocImpl)prototype.clone();
+ String dimSuffix="";
+ while (fieldDef.trim().endsWith("[")
+ || fieldDef.trim().endsWith("]")) {
+ fieldDef=fieldDef.trim();
+ dimSuffix=fieldDef.charAt(fieldDef.length()-1)+dimSuffix;
+ fieldDef=fieldDef.substring(0,fieldDef.length()-1);
+ }
+
+ fieldDoc.setTypeName(fieldDoc.getTypeName()+dimSuffix);
+ fieldDoc.setName(fieldDef.trim());
+ fieldDoc.setValueLiteral(fieldValueLiteral);
+ return fieldDoc;
+ }
+ catch (CloneNotSupportedException e) {
+ // should not happen
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Collection createFromSource(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ char[] source, int startIndex, int endIndex) {
+
+ List rcList=new ArrayList();
+
+ FieldDocImpl fd=new FieldDocImpl(containingClass,
+ containingPackage,
+ DocImpl.getPosition(containingClass, source, startIndex));
+
+ int ndx=fd.parseModifiers(source, startIndex, endIndex);
+
+ if (containingClass.isInterface()) {
+ fd.accessLevel = ACCESS_PUBLIC;
+ }
+
+ final int STATE_FIELDNAME = 1;
+ final int STATE_FIELDVALUE = 2;
+ final int STATE_QUOTE = 3;
+ final int STATE_QUOTEBS = 4;
+ final int STATE_SQUOTE = 5;
+ final int STATE_SQUOTEBS = 6;
+ final int STATE_COMMENT = 7;
+ final int STATE_LINECOMMENT = 8;
+
+ int lastFieldDefStart = ndx;
+ int state = STATE_FIELDNAME;
+ int prevState = state;
+
+ int bracketCount = 0;
+
+ StringBuffer fieldNameBuf = new StringBuffer();
+ StringBuffer fieldValueLiteralBuf = new StringBuffer();
+
+ for (int i=ndx; i<endIndex; ++i) {
+
+ char c = source[i];
+ char nextChar = '\0';
+ if (i + 1 < endIndex) {
+ nextChar = source[i + 1];
+ }
+ switch (state) {
+ case STATE_FIELDNAME:
+ if ('/' == c && '/' == nextChar) {
+ prevState = state;
+ state = STATE_LINECOMMENT;
+ }
+ else if ('/' == c && '*' == nextChar) {
+ prevState = state;
+ state = STATE_COMMENT;
+ }
+ else if (',' == c || ';' == c) {
+ rcList.add(createFieldDoc(fd, fieldNameBuf.toString(), null));
+ fieldNameBuf.setLength(0);
+ }
+ else if ('=' == c) {
+ state = STATE_FIELDVALUE;
+ }
+ else if (!(' ' == c || '\n' == c || '\r' == c || '\t' == c)) {
+ fieldNameBuf.append(c);
+ }
+ break;
+
+ case STATE_FIELDVALUE:
+ if ('/' == c && '/' == nextChar) {
+ prevState = state;
+ state = STATE_LINECOMMENT;
+ }
+ else if ('/' == c && '*' == nextChar) {
+ prevState = state;
+ state = STATE_COMMENT;
+ }
+ else if ('\"' == c) {
+ prevState = state;
+ state = STATE_QUOTE;
+ fieldValueLiteralBuf.append(c);
+ }
+ else if ('\'' == c) {
+ prevState = state;
+ state = STATE_SQUOTE;
+ fieldValueLiteralBuf.append(c);
+ }
+ else if ('{' == c || '(' == c) {
+ ++ bracketCount;
+ fieldValueLiteralBuf.append(c);
+ }
+ else if ('}' == c || ')' == c) {
+ -- bracketCount;
+ fieldValueLiteralBuf.append(c);
+ }
+ else if (0 == bracketCount && (',' == c || ';' == c)) {
+ rcList.add(createFieldDoc(fd, fieldNameBuf.toString(),
+ fieldValueLiteralBuf.toString()));
+ fieldNameBuf.setLength(0);
+ fieldValueLiteralBuf.setLength(0);
+ state = STATE_FIELDNAME;
+ }
+ else {
+ fieldValueLiteralBuf.append(c);
+ }
+ break;
+
+ case STATE_QUOTE:
+ fieldValueLiteralBuf.append(c);
+ if ('\\' == c) {
+ state = STATE_QUOTEBS;
+ }
+ else if ('\"' == c) {
+ state = prevState;
+ }
+ break;
+
+ case STATE_SQUOTE:
+ fieldValueLiteralBuf.append(c);
+ if ('\\' == c) {
+ state = STATE_SQUOTEBS;
+ }
+ else if ('\'' == c) {
+ state = prevState;
+ }
+ break;
+
+ case STATE_QUOTEBS:
+ fieldValueLiteralBuf.append(c);
+ state = STATE_QUOTE;
+ break;
+
+ case STATE_SQUOTEBS:
+ fieldValueLiteralBuf.append(c);
+ state = STATE_SQUOTE;
+ break;
+
+ case STATE_LINECOMMENT:
+ if ('\n' == c) {
+ state = prevState;
+ }
+ break;
+
+ case STATE_COMMENT:
+ if ('*' == c && '/' == nextChar) {
+ ++ i;
+ state = prevState;
+ }
+ break;
+ }
+ }
+
+ if (fieldNameBuf.length() > 0) {
+ rcList.add(createFieldDoc(fd, fieldNameBuf.toString(),
+ fieldValueLiteralBuf.toString()));
+ }
+
+ return rcList;
+ }
+
+ public boolean isField() {
+ return true;
+ }
+
+ public boolean isTransient() { return isTransient; }
+
+ public boolean isVolatile() { return isVolatile; }
+
+ public SerialFieldTag[] serialFieldTags() { return new SerialFieldTag[0]; }
+
+ public int modifierSpecifier() {
+ return super.modifierSpecifier()
+ | (isVolatile()?Modifier.VOLATILE:0)
+ | (isTransient()?Modifier.TRANSIENT:0)
+ ;
+ }
+
+ protected boolean processModifier(String word) {
+ if (super.processModifier(word)) {
+ return true;
+ }
+ else if (word.equals("transient")) {
+ isTransient=true;
+ return true;
+ }
+ else if (word.equals("volatile")) {
+ isVolatile=true;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ void resolve() {
+ resolveTags();
+ }
+
+ public boolean hasSerialTag() {
+ return true; //tagMap.get("serial")!=null;
+ }
+
+ public String toString() { return name(); }
+
+ public Object constantValue() {
+ return constantValue(new HashSet());
+ }
+
+ public Object constantValue(Set visitedFields) {
+ if (!isStatic()
+ || !isFinal()
+ || (!type().isPrimitive() && !"java.lang.String".equals(type().qualifiedTypeName()))
+ || type.dimension().length()>0
+ || null == valueLiteral) {
+
+ return null;
+
+ }
+ else {
+ if (!constantValueEvaluated) {
+
+ visitedFields.add(this);
+
+ String expression = "(" + type().typeName() + ")(" + valueLiteral + ")";
+ try {
+ this.constantValue = Evaluator.evaluate(expression,
+ visitedFields,
+ (ClassDocImpl)containingClass());
+ }
+ catch (CircularExpressionException e) {
+ // FIXME: This should use the error reporter
+ System.err.println("WARNING: Cannot resolve expression for field " + containingClass.qualifiedTypeName() + "." + name() + ": " + e.getMessage());
+ }
+ catch (IllegalExpressionException ignore) {
+ }
+ constantValueEvaluated = true;
+ }
+ return this.constantValue;
+ }
+ }
+
+ private static void appendCharString(StringBuffer result, char c, boolean inSingleCuotes)
+ {
+ switch (c) {
+ case '\b': result.append("\\b"); break;
+ case '\t': result.append("\\t"); break;
+ case '\n': result.append("\\n"); break;
+ case '\f': result.append("\\f"); break;
+ case '\r': result.append("\\r"); break;
+ case '\"': result.append("\\\""); break;
+ case '\'': result.append(inSingleCuotes ? "\\'" : "'"); break;
+ default:
+ if (c >= 32 && c <= 127) {
+ result.append(c);
+ }
+ else {
+ result.append("\\u");
+ String hexValue = Integer.toString((int)c, 16);
+ int zeroCount = 4 - hexValue.length();
+ for (int i=0; i<zeroCount; ++i) {
+ result.append('0');
+ }
+ result.append(hexValue);
+ }
+ }
+ }
+
+ public String constantValueExpression() {
+ Object value = constantValue();
+
+ if (null == value) {
+ return "null";
+ }
+ else if (value instanceof String) {
+ StringBuffer result = new StringBuffer("\"");
+ char[] chars = ((String)value).toCharArray();
+ for (int i=0; i<chars.length; ++i) {
+ appendCharString(result, chars[i], false);
+ }
+ result.append("\"");
+ return result.toString();
+ }
+ else if (value instanceof Float) {
+ return value.toString() + "f";
+ }
+ else if (value instanceof Long) {
+ return value.toString() + "L";
+ }
+ else if (value instanceof Character) {
+ StringBuffer result = new StringBuffer("'");
+ appendCharString(result, ((Character)value).charValue(), false);
+ result.append("'");
+ return result.toString();
+ }
+ else /* if (value instanceof Double
+ || value instanceof Integer
+ || value instanceof Short
+ || value instanceof Byte) */ {
+ return value.toString();
+ }
+ }
+
+ void setValueLiteral(String valueLiteral)
+ {
+ this.valueLiteral = valueLiteral;
+ }
+
+ public boolean isStatic()
+ {
+ return super.isStatic() || containingClass().isInterface();
+ }
+
+ public boolean isFinal()
+ {
+ return super.isFinal() || containingClass().isInterface();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocPackageDoc.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocPackageDoc.java
new file mode 100644
index 000000000..4cfbbe451
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocPackageDoc.java
@@ -0,0 +1,56 @@
+/* gnu.classpath.tools.gjdoc.GjdocPackageDoc
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.io.File;
+import com.sun.javadoc.PackageDoc;
+
+/**
+ * Extension of the PackageDoc interface which additionally provides
+ * the directory the package's source files are located in.
+ *
+ * @author Julian Scheid
+ */
+public interface GjdocPackageDoc extends PackageDoc
+{
+ /**
+ * Returns the directory this package's source files are located
+ * in.
+ */
+ public File packageDirectory();
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocRootDoc.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocRootDoc.java
new file mode 100644
index 000000000..d45786fb9
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/GjdocRootDoc.java
@@ -0,0 +1,56 @@
+/* gnu.classpath.tools.gjdoc.GjdocRootDoc
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.io.File;
+import com.sun.javadoc.RootDoc;
+
+/**
+ * Extension of the RootDoc interface which additionally provides
+ * a method for flushing all state.
+ *
+ * @author Julian Scheid
+ */
+public interface GjdocRootDoc extends RootDoc
+{
+ /**
+ * Invalidate this RootDoc by flushing all associated data, but
+ * keep its error reporting functionality intact.
+ */
+ public void flush();
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/InheritDocTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/InheritDocTagImpl.java
new file mode 100644
index 000000000..3be63dd79
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/InheritDocTagImpl.java
@@ -0,0 +1,103 @@
+/* gnu.classpath.tools.gjdoc.InheritDocTagImpl
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+
+/**
+ * Represents the <code>inheritDoc</code> tag.
+ */
+public class InheritDocTagImpl
+ extends AbstractTagImpl
+{
+ private ClassDocImpl contextClass;
+ private MemberDocImpl contextMember;
+ private AbstractTagImpl contextTag;
+
+ public InheritDocTagImpl(ClassDocImpl contextClass,
+ MemberDocImpl contextMember,
+ AbstractTagImpl contextTag)
+ {
+ super("");
+ this.contextClass = contextClass;
+ this.contextMember = contextMember;
+ this.contextTag = contextTag;
+ }
+
+ public String kind() {
+ return "@inheritDoc";
+ }
+
+ public String name() {
+ return "@inheritDoc";
+ }
+
+ private TagContainer inheritedDoc;
+ private boolean inheritedDocInitialized = false;
+
+ private TagContainer getInheritedDoc()
+ {
+ if (!inheritedDocInitialized) {
+ inheritedDoc = DocImpl.findInheritedDoc(contextClass, contextMember, contextTag);
+ inheritedDocInitialized = true;
+ }
+ return inheritedDoc;
+ }
+
+ public Tag[] firstSentenceTags() {
+ TagContainer _inheritedDoc = getInheritedDoc();
+ if (_inheritedDoc != null) {
+ return _inheritedDoc.firstSentenceTags();
+ }
+ else {
+ return null;
+ }
+ }
+
+ public Tag[] inlineTags() {
+ TagContainer _inheritedDoc = getInheritedDoc();
+ if (_inheritedDoc != null) {
+ return _inheritedDoc.inlineTags();
+ }
+ else {
+ return null;
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/JavadocWrapper.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/JavadocWrapper.java
new file mode 100644
index 000000000..93c08b94d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/JavadocWrapper.java
@@ -0,0 +1,53 @@
+/* gnu.classpath.tools.gjdoc.JavadocWrapper
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.util.*;
+import java.io.*;
+import com.sun.javadoc.*;
+
+public class JavadocWrapper {
+
+ public static void main(String[] args) throws Exception {
+
+ Timer.setStartTime();
+ Class sunJavadocMain=Class.forName("com.sun.tools.javadoc.Main");
+ sunJavadocMain.getMethod("main", new Class[]{String[].class}).invoke(null, new Object[]{args});
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/LinkTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/LinkTagImpl.java
new file mode 100644
index 000000000..3b2b8a848
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/LinkTagImpl.java
@@ -0,0 +1,63 @@
+/* gnu.classpath.tools.gjdoc.LinkTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+
+public class LinkTagImpl extends SeeTagImpl {
+
+ private String name;
+
+ public LinkTagImpl(String name, String _text, ClassDocImpl contextClass) {
+ super(_text, contextClass);
+ this.name = name;
+ }
+
+ public String name() { return name; }
+
+ public Tag[] firstSentenceTags() {
+ return new Tag[0]; //inlineTags();
+ }
+
+ public Tag[] inlineTags() {
+ return new Tag[0]; //new Tag[]{new TextTagImpl(referencedClassName)};
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Main.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Main.java
new file mode 100644
index 000000000..ce9e96d82
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Main.java
@@ -0,0 +1,1854 @@
+/* gnu.classpath.tools.gjdoc.Main
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.*;
+import java.text.Collator;
+
+import gnu.classpath.tools.FileSystemClassLoader;
+
+/**
+ * Class that will launch the gjdoc tool.
+ */
+public final class Main
+{
+
+ /**
+ * Do we load classes that are referenced as base class?
+ */
+ static final boolean DESCEND_SUPERCLASS = true;
+
+ /**
+ * Do we load classes that are referenced as interface?
+ */
+ static final boolean DESCEND_INTERFACES = false;
+
+ /**
+ * Do we load classes that are imported in a source file?
+ */
+ static final boolean DESCEND_IMPORTED = true;
+
+ /**
+ * Document only public members.
+ */
+ static final int COVERAGE_PUBLIC = 0;
+
+ /**
+ * Document only public and protected members.
+ */
+ static final int COVERAGE_PROTECTED = 1;
+
+ /**
+ * Document public, protected and package private members.
+ */
+ static final int COVERAGE_PACKAGE = 2;
+
+ /**
+ * Document all members.
+ */
+ static final int COVERAGE_PRIVATE = 3;
+
+ /*
+ * FIXME: This should come from a ResourceBundle
+ */
+ private static final String STRING_TRY_GJDOC_HELP =
+ "Try `gjdoc --help' for more information.";
+
+ /**
+ * Grid for looking up whether a particular access level is included in the
+ * documentation.
+ */
+ static final boolean[][] coverageTemplates = new boolean[][]
+ { new boolean[]
+ { true, false, false, false }, // public
+ new boolean[]
+ { true, true, false, false }, // protected
+ new boolean[]
+ { true, true, true, false }, // package
+ new boolean[]
+ { true, true, true, true }, // private
+ };
+
+ /**
+ * Holds the Singleton instance of this class.
+ */
+ private static Main instance = new Main();
+
+ /**
+ * Avoid re-instantiation of this class.
+ */
+ private Main()
+ {
+ }
+
+ private static RootDocImpl rootDoc;
+
+ private ErrorReporter reporter;
+
+ /**
+ * Cache for version string from resource /version.properties
+ */
+ private String gjdocVersion;
+
+ /**
+ * <code>false</code> during Phase I: preparation of the documentation data.
+ * <code>true</code> during Phase II: documentation output by doclet.
+ */
+ boolean docletRunning = false;
+
+ //---- Command line options
+
+ /**
+ * Option "-doclet": name of the Doclet class to use.
+ */
+ private String option_doclet = "gnu.classpath.tools.doclets.htmldoclet.HtmlDoclet";
+
+ /**
+ * Option "-overview": path to the special overview file.
+ */
+ private String option_overview;
+
+ /**
+ * Option "-coverage": which members to include in generated documentation.
+ */
+ private int option_coverage = COVERAGE_PROTECTED;
+
+ /**
+ * Option "-help": display command line usage.
+ */
+ private boolean option_help;
+
+ /**
+ * Option "-docletpath": path to doclet classes.
+ */
+ private String option_docletpath;
+
+ /**
+ * Option "-classpath": path to additional classes.
+ */
+ private String option_classpath;
+
+ /**
+ * Option "-sourcepath": path to the Java source files to be documented.
+ * FIXME: this should be a list of paths
+ */
+ private List option_sourcepath = new ArrayList();
+
+ /**
+ * Option "-extdirs": path to Java extension files.
+ */
+ private String option_extdirs;
+
+ /**
+ * Option "-verbose": Be verbose when generating documentation.
+ */
+ private boolean option_verbose;
+
+ /**
+ * Option "-nowarn": Do not print warnings.
+ */
+ private boolean option_nowarn;
+
+ /**
+ * Option "-locale:" Specify the locale charset of Java source files.
+ */
+ private Locale option_locale = new Locale("en", "us");
+
+ /**
+ * Option "-encoding": Specify character encoding of Java source files.
+ */
+ private String option_encoding;
+
+ /**
+ * Option "-J": Specify flags to be passed to Java runtime.
+ */
+ private List option_java_flags = new LinkedList(); //ArrayList();
+
+ /**
+ * Option "-source:" should be 1.4 to handle assertions, 1.1 is no
+ * longer supported.
+ */
+ private String option_source = "1.2";
+
+ /**
+ * Option "-subpackages": list of subpackages to be recursively
+ * added.
+ */
+ private List option_subpackages = new ArrayList();
+
+ /**
+ * Option "-exclude": list of subpackages to exclude.
+ */
+ private List option_exclude = new ArrayList();
+
+ /**
+ * Option "-breakiterator" - whether to use BreakIterator for
+ * detecting the end of the first sentence.
+ */
+ private boolean option_breakiterator;
+
+ /**
+ * Option "-licensetext" - whether to copy license text.
+ */
+ private boolean option_licensetext;
+
+ /**
+ * The locale-dependent collator used for sorting.
+ */
+ private Collator collator;
+
+ /**
+ * true when --version has been specified on the command line.
+ */
+ private boolean option_showVersion;
+
+ /**
+ * true when -bootclasspath has been specified on the command line.
+ */
+ private boolean option_bootclasspath_specified;
+
+ /**
+ * true when -all has been specified on the command line.
+ */
+ private boolean option_all;
+
+ /**
+ * true when -reflection has been specified on the command line.
+ */
+ private boolean option_reflection;
+
+ // TODO: add the rest of the options as instance variables
+
+ /**
+ * Parse all source files/packages and subsequentially start the Doclet given
+ * on the command line.
+ *
+ * @param allOptions List of all command line tokens
+ */
+ private boolean startDoclet(List allOptions)
+ {
+
+ try
+ {
+
+ //--- Fetch the Class object for the Doclet.
+
+ Debug.log(1, "loading doclet class...");
+
+ Class docletClass;
+
+ if (null != option_docletpath) {
+ try {
+ FileSystemClassLoader docletPathClassLoader
+ = new FileSystemClassLoader(option_docletpath);
+ System.err.println("trying to load class " + option_doclet + " from path " + option_docletpath);
+ docletClass = docletPathClassLoader.findClass(option_doclet);
+ }
+ catch (Exception e) {
+ docletClass = Class.forName(option_doclet);
+ }
+ }
+ else {
+ docletClass = Class.forName(option_doclet);
+ }
+ //Object docletInstance = docletClass.newInstance();
+
+ Debug.log(1, "doclet class loaded...");
+
+ Method startTempMethod = null;
+ Method startMethod = null;
+ Method optionLenMethod = null;
+ Method validOptionsMethod = null;
+
+ //--- Try to find the optionLength method in the Doclet class.
+
+ try
+ {
+ optionLenMethod = docletClass.getMethod("optionLength", new Class[]
+ { String.class });
+ }
+ catch (NoSuchMethodException e)
+ {
+ // Ignore if not found; it's OK it the Doclet class doesn't define
+ // this method.
+ }
+
+ //--- Try to find the validOptions method in the Doclet class.
+
+ try
+ {
+ validOptionsMethod = docletClass.getMethod("validOptions", new Class[]
+ { String[][].class, DocErrorReporter.class });
+ }
+ catch (NoSuchMethodException e)
+ {
+ // Ignore if not found; it's OK it the Doclet class doesn't define
+ // this method.
+ }
+
+ //--- Find the start method in the Doclet class; complain if not found
+
+ try
+ {
+ startTempMethod = docletClass.getMethod("start", new Class[]
+ { TemporaryStore.class });
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ startMethod = docletClass.getMethod("start", new Class[]
+ { RootDoc.class });
+
+ //--- Feed the custom command line tokens to the Doclet
+
+ // stores all recognized options
+ List options = new LinkedList();
+
+ // stores packages and classes defined on the command line
+ List packageAndClasses = new LinkedList();
+
+ for (Iterator it = allOptions.iterator(); it.hasNext();)
+ {
+ String option = (String) it.next();
+
+ Debug.log(9, "parsing option '" + option + "'");
+
+ if (option.startsWith("-"))
+ {
+
+ //--- Parse option
+
+ int optlen = optionLength(option);
+
+ //--- Try to get option length from Doclet class
+
+ if (optlen <= 0 && optionLenMethod != null)
+ {
+
+ optionLenMethod.invoke(null, new Object[]
+ { option });
+
+ Debug.log(3, "invoking optionLen method");
+
+ optlen = ((Integer) optionLenMethod.invoke(null, new Object[]
+ { option })).intValue();
+
+ Debug.log(3, "done");
+ }
+
+ if (optlen <= 0) {
+
+ if (option.startsWith("-JD")) {
+ // Simulate VM option -D
+ String propertyValue = option.substring(3);
+ int ndx = propertyValue.indexOf('=');
+ if (ndx <= 0) {
+ reporter.printError("Illegal format in option " + option + ": use -JDproperty=value");
+ return false;
+ }
+ else {
+ String property = propertyValue.substring(0, ndx);
+ String value = propertyValue.substring(ndx + 1);
+ System.setProperty(property, value);
+ }
+ }
+ else if (option.startsWith("-J")) {
+ //--- Warn if VM option is encountered
+ reporter.printWarning("Ignored option " + option + ". Pass this option to the VM if required.");
+ }
+ else {
+ //--- Complain if not found
+
+ reporter.printError("Unknown option " + option);
+ reporter.printNotice(STRING_TRY_GJDOC_HELP);
+ return false;
+ }
+ }
+ else
+ {
+
+ //--- Read option values
+
+ String[] optionAndValues = new String[optlen];
+ optionAndValues[0] = option;
+ for (int i = 1; i < optlen; ++i)
+ {
+ if (!it.hasNext())
+ {
+ reporter.printError("Missing value for option " + option);
+ return false;
+ }
+ else
+ {
+ optionAndValues[i] = (String) it.next();
+ }
+ }
+
+ //--- Store option for processing later
+
+ options.add(optionAndValues);
+ }
+ }
+ else if (option.length() > 0)
+ {
+
+ //--- Add to list of packages/classes if not option or option
+ // value
+
+ packageAndClasses.add(option);
+ }
+ }
+
+ Debug.log(9, "options parsed...");
+
+ //--- For each package specified with the -subpackages option on
+ // the command line, recursively find all valid java files
+ // beneath it.
+
+ //--- For each class or package specified on the command line,
+ // check that it exists and find out whether it is a class
+ // or a package
+
+ for (Iterator it = option_subpackages.iterator(); it.hasNext();)
+ {
+ String subpackage = (String) it.next();
+ Set foundPackages = new LinkedHashSet();
+
+ for (Iterator pit = option_sourcepath.iterator(); pit.hasNext(); ) {
+ File sourceDir = (File)pit.next();
+ File packageDir = new File(sourceDir, subpackage.replace('.', File.separatorChar));
+ findPackages(subpackage, packageDir, foundPackages);
+ }
+
+ addFoundPackages(subpackage, foundPackages);
+ }
+
+ if (option_all) {
+ Set foundPackages = new LinkedHashSet();
+ for (Iterator pit = option_sourcepath.iterator(); pit.hasNext(); ) {
+ File sourceDir = (File)pit.next();
+ findPackages("", sourceDir, foundPackages);
+ }
+ addFoundPackages(null, foundPackages);
+ for (Iterator packageIt = foundPackages.iterator(); packageIt.hasNext(); ) {
+ String packageName = (String)packageIt.next();
+ if (null == packageName) {
+ packageName = "";
+ }
+ rootDoc.addSpecifiedPackageName(packageName);
+ }
+ }
+
+ for (Iterator it = packageAndClasses.iterator(); it.hasNext();)
+ {
+
+ String classOrPackage = (String) it.next();
+
+ boolean foundSourceFile = false;
+
+ if (classOrPackage.endsWith(".java")) {
+ for (Iterator pit = option_sourcepath.iterator(); pit.hasNext() && !foundSourceFile; ) {
+ File sourceDir = (File)pit.next();
+ File sourceFile = new File(sourceDir, classOrPackage);
+ if (sourceFile.exists() && !sourceFile.isDirectory()) {
+ rootDoc.addSpecifiedSourceFile(sourceFile);
+ foundSourceFile = true;
+ break;
+ }
+ }
+ if (!foundSourceFile) {
+ File sourceFile = new File(classOrPackage);
+ if (sourceFile.exists() && !sourceFile.isDirectory()) {
+ rootDoc.addSpecifiedSourceFile(sourceFile);
+ foundSourceFile = true;
+ }
+ }
+ }
+
+ if (!foundSourceFile) {
+ //--- Check for illegal name
+
+ if (classOrPackage.startsWith(".")
+ || classOrPackage.endsWith(".")
+ || classOrPackage.indexOf("..") > 0
+ || !checkCharSet(classOrPackage,
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_."))
+ {
+ throw new ParseException("Illegal class or package name '"
+ + classOrPackage + "'");
+ }
+
+ //--- Assemble absolute path to package
+
+ String classOrPackageRelPath = classOrPackage.replace('.',
+ File.separatorChar);
+
+ //--- Create one file object each for a possible package directory
+ // and a possible class file, and find out if they exist.
+
+ List packageDirs = rootDoc.findSourceFiles(classOrPackageRelPath);
+ List sourceFiles = rootDoc.findSourceFiles(classOrPackageRelPath + ".java");
+
+ boolean packageDirExists = !packageDirs.isEmpty();
+ boolean sourceFileExists = !sourceFiles.isEmpty();
+
+ //--- Complain if neither exists: not found
+
+ if (!packageDirExists && !sourceFileExists)
+ {
+ reporter.printError("Class or package " + classOrPackage
+ + " not found.");
+ return false;
+ }
+
+ //--- Complain if both exist: ambigious
+
+ else
+ if (packageDirExists && sourceFileExists)
+ {
+ reporter.printError("Ambigious class/package name "
+ + classOrPackage + ".");
+ return false;
+ }
+
+ //--- Otherwise, if the package directory exists, it is a package
+
+ else
+ if (packageDirExists) {
+ Iterator packageDirIt = packageDirs.iterator();
+ boolean packageDirFound = false;
+ while (packageDirIt.hasNext()) {
+ File packageDir = (File)packageDirIt.next();
+ if (packageDir.isDirectory()) {
+ rootDoc.addSpecifiedPackageName(classOrPackage);
+ packageDirFound = true;
+ break;
+ }
+ }
+ if (!packageDirFound) {
+ reporter.printError("No suitable file or directory found for" + classOrPackage);
+ return false;
+ }
+ }
+
+ //--- Otherwise, emit error message
+
+ else {
+ reporter.printError("No sources files found for package " + classOrPackage);
+ }
+ }
+ }
+
+ //--- Complain if no packages or classes specified
+
+ if (option_help) {
+ usage();
+ return true;
+ }
+
+ //--- Validate custom options passed on command line
+ // by asking the Doclet if they are OK.
+
+ String[][] customOptionArr = (String[][]) options
+ .toArray(new String[0][0]);
+ if (validOptionsMethod != null
+ && !((Boolean) validOptionsMethod.invoke(null, new Object[]
+ { customOptionArr, reporter })).booleanValue())
+ {
+ // Not ok: shutdown system.
+ reporter.printNotice(STRING_TRY_GJDOC_HELP);
+ return false;
+ }
+
+ if (!rootDoc.hasSpecifiedPackagesOrClasses()) {
+ reporter.printError("No packages or classes specified.");
+ reporter.printNotice(STRING_TRY_GJDOC_HELP);
+ return false;
+ }
+
+ rootDoc.setOptions(customOptionArr);
+
+ rootDoc.build();
+
+ //--- Bail out if no classes found
+
+ if (0 == rootDoc.classes().length
+ && 0 == rootDoc.specifiedPackages().length
+ && 0 == rootDoc.specifiedClasses().length)
+ {
+ reporter.printError("No packages or classes found(!).");
+ return false;
+ }
+
+ //--- Our work is done, tidy up memory
+
+ System.gc();
+ System.gc();
+
+ //--- Set flag indicating Phase II of documentation generation
+
+ docletRunning = true;
+
+ //--- Invoke the start method on the Doclet: produce output
+
+ reporter.printNotice("Running doclet...");
+
+ TemporaryStore tstore = new TemporaryStore(Main.rootDoc);
+
+ Thread.currentThread().setContextClassLoader(docletClass.getClassLoader());
+
+ if (null != startTempMethod)
+ {
+ startTempMethod.invoke(null, new Object[]
+ { tstore });
+ }
+ else
+ {
+ startMethod.invoke(null, new Object[]
+ { tstore.getAndClear() });
+ }
+
+ //--- Let the user know how many warnings/errors occured
+
+ if (reporter.getWarningCount() > 0)
+ {
+ reporter.printNotice(reporter.getWarningCount() + " warnings");
+ }
+
+ if (reporter.getErrorCount() > 0)
+ {
+ reporter.printNotice(reporter.getErrorCount() + " errors");
+ }
+
+ System.gc();
+
+ //--- Done.
+ return true;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ private void addFoundPackages(String subpackage, Set foundPackages)
+ {
+ if (foundPackages.isEmpty()) {
+ reporter.printWarning("No classes found under subpackage " + subpackage);
+ }
+ else {
+ boolean onePackageAdded = false;
+ for (Iterator rit = foundPackages.iterator(); rit.hasNext();) {
+ String foundPackage = (String)rit.next();
+ boolean excludeThisPackage = false;
+
+ for (Iterator eit = option_exclude.iterator(); eit.hasNext();) {
+ String excludePackage = (String)eit.next();
+ if (foundPackage.equals(excludePackage) ||
+ foundPackage.startsWith(excludePackage + ":")) {
+ excludeThisPackage = true;
+ break;
+ }
+ }
+
+ if (!excludeThisPackage) {
+ rootDoc.addSpecifiedPackageName(foundPackage);
+ onePackageAdded = true;
+ }
+ }
+ if (!onePackageAdded) {
+ if (null != subpackage) {
+ reporter.printWarning("No non-excluded classes found under subpackage " + subpackage);
+ }
+ else {
+ reporter.printWarning("No non-excluded classes found.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Verify that the given file is a valid Java source file and that
+ * it specifies the given package.
+ */
+ private boolean isValidJavaFile(File file,
+ String expectedPackage)
+ {
+ try {
+ InputStream in = new BufferedInputStream(new FileInputStream(file));
+
+ int ch, prevChar = 0;
+
+ final int STATE_DEFAULT = 0;
+ final int STATE_COMMENT = 1;
+ final int STATE_LINE_COMMENT = 2;
+
+ int state = STATE_DEFAULT;
+
+ StringBuffer word = new StringBuffer();
+ int wordIndex = 0;
+
+ while ((ch = in.read()) >= 0) {
+ String completeWord = null;
+
+ switch (state) {
+ case STATE_COMMENT:
+ if (prevChar == '*' && ch == '/') {
+ state = STATE_DEFAULT;
+ }
+ break;
+
+ case STATE_LINE_COMMENT:
+ if (ch == '\n') {
+ state = STATE_DEFAULT;
+ }
+ break;
+
+ case STATE_DEFAULT:
+ if (prevChar == '/' && ch == '*') {
+ word.deleteCharAt(word.length() - 1);
+ if (word.length() > 0) {
+ completeWord = word.toString();
+ word.setLength(0);
+ }
+ state = STATE_COMMENT;
+ }
+ else if (prevChar == '/' && ch == '/') {
+ word.deleteCharAt(word.length() - 1);
+ if (word.length() > 0) {
+ completeWord = word.toString();
+ word.setLength(0);
+ }
+ state = STATE_LINE_COMMENT;
+ }
+ else if (" \t\r\n".indexOf(ch) >= 0) {
+ if (word.length() > 0) {
+ completeWord = word.toString();
+ word.setLength(0);
+ }
+ }
+ else if (1 == wordIndex && ';' == ch) {
+ if (word.length() > 0) {
+ completeWord = word.toString();
+ word.setLength(0);
+ }
+ else {
+ // empty package name in source file: "package ;" -> invalid source file
+ in.close();
+ return false;
+ }
+ }
+ else {
+ word.append((char)ch);
+ }
+ break;
+ }
+
+ if (null != completeWord) {
+ if (0 == wordIndex && !"package".equals(completeWord)) {
+ in.close();
+ return "".equals(expectedPackage);
+ }
+ else if (1 == wordIndex) {
+ in.close();
+ return expectedPackage.equals(completeWord);
+ }
+ ++ wordIndex;
+ }
+
+ prevChar = ch;
+ }
+
+ // no package or class found before end-of-file -> invalid source file
+
+ in.close();
+ return false;
+ }
+ catch (IOException e) {
+ reporter.printWarning("Could not examine file " + file + ": " + e);
+ return false;
+ }
+ }
+
+ /**
+ * Recursively try to locate valid Java packages under the given
+ * package specified by its name and its directory. Add the names
+ * of all valid packages to the result list.
+ */
+ private void findPackages(String subpackage,
+ File packageDir,
+ Set result)
+ {
+ File[] files = packageDir.listFiles();
+ if (null != files) {
+ for (int i=0; i<files.length; ++i) {
+ File file = files[i];
+ if (!file.isDirectory() && file.getName().endsWith(".java")) {
+ if (isValidJavaFile(file, subpackage)) {
+ if ("".equals(subpackage)) {
+ result.add(null);
+ }
+ else {
+ result.add(subpackage);
+ }
+ break;
+ }
+ }
+ }
+ for (int i=0; i<files.length; ++i) {
+ File file = files[i];
+ if (file.isDirectory()) {
+ String newSubpackage;
+ if (null != subpackage && subpackage.length() > 0) {
+ newSubpackage = subpackage + "." + file.getName();
+ }
+ else {
+ newSubpackage = file.getName();
+ }
+ findPackages(newSubpackage, file, result);
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private static boolean validOptions(String options[][],
+ DocErrorReporter reporter)
+ {
+
+ boolean foundDocletOption = false;
+ for (int i = 0; i < options.length; i++)
+ {
+ String[] opt = options[i];
+ if (opt[0].equalsIgnoreCase("-doclet"))
+ {
+ if (foundDocletOption)
+ {
+ reporter.printError("Only one -doclet option allowed.");
+ return false;
+ }
+ else
+ {
+ foundDocletOption = true;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Main entry point. This is the method called when gjdoc is invoked from the
+ * command line.
+ *
+ * @param args
+ * command line arguments
+ */
+ public static void main(String[] args)
+ {
+
+ try
+ {
+ //--- Remember current time for profiling purposes
+
+ Timer.setStartTime();
+
+ //--- Handle control to the Singleton instance of this class
+
+ int result = instance.start(args);
+
+ if (result < 0) {
+ // fatal error
+ System.exit(5);
+ }
+ else if (result > 0) {
+ // errors encountered
+ System.exit(1);
+ }
+ else {
+ // success
+ System.exit(0);
+ }
+ }
+ catch (Exception e)
+ {
+ //--- unexpected error
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Parses command line arguments and subsequentially handles control to the
+ * startDoclet() method
+ *
+ * @param args The command line parameters.
+ */
+ public static int execute(String[] args)
+ {
+ try
+ {
+ int result = instance.start(args);
+ if (result < 0) {
+ // fatal error
+ return 5;
+ }
+ else if (result > 0) {
+ // errors encountered
+ return 1;
+ }
+ else {
+ // success
+ return 0;
+ }
+ }
+ catch (Exception e)
+ {
+ // unexpected error
+ return 1;
+ }
+ }
+
+ /**
+ * @param programName Name of the program (for error messages). *disregarded*
+ * @param args The command line parameters.
+ * @returns The return code.
+ */
+ public static int execute(String programName,
+ String[] args)
+ {
+ return execute(args);
+ }
+
+ /**
+ * @param programName Name of the program (for error messages).
+ * @param defaultDocletClassName Fully qualified class name.
+ * @param args The command line parameters.
+ * @returns The return code.
+ *//*
+ public static int execute(String programName,
+ String defaultDocletClassName,
+ String[] args)
+ {
+ // not yet implemented
+ }*/
+
+ /**
+ * @param programName Name of the program (for error messages).
+ * @param defaultDocletClassName Fully qualified class name.
+ * @param args The command line parameters.
+ * @returns The return code.
+ *//*
+ public static int execute(String programName,
+ String defaultDocletClassName,
+ String[] args)
+ {
+ // not yet implemented
+ }*/
+
+ /**
+ * @param programName Name of the program (for error messages).
+ * @param errWriter PrintWriter to receive error messages.
+ * @param warnWriter PrintWriter to receive error messages.
+ * @param noticeWriter PrintWriter to receive error messages.
+ * @param defaultDocletClassName Fully qualified class name.
+ * @param args The command line parameters.
+ * @returns The return code.
+ *//*
+ public static int execute(String programName,
+ PrintWriter errWriter,
+ PrintWriter warnWriter,
+ PrintWriter noticeWriter,
+ String defaultDocletClassName,
+ String[] args)
+ {
+ // not yet implemented
+ }*/
+
+ /**
+ * Parses command line arguments and subsequentially handles control to the
+ * startDoclet() method
+ *
+ * @param args
+ * Command line arguments, as passed to the main() method
+ * @return {@code -1} in case of a fatal error (invalid arguments),
+ * or the number of errors encountered.
+ * @exception ParseException
+ * FIXME
+ * @exception IOException
+ * if an IO problem occur
+ */
+ public int start(String[] args) throws ParseException, IOException
+ {
+
+ //--- Collect unparsed arguments in array and resolve references
+ // to external argument files.
+
+ List arguments = new ArrayList(args.length);
+
+ for (int i = 0; i < args.length; ++i)
+ {
+ if (!args[i].startsWith("@"))
+ {
+ arguments.add(args[i]);
+ }
+ else
+ {
+ FileReader reader = new FileReader(args[i].substring(1));
+ StreamTokenizer st = new StreamTokenizer(reader);
+ st.resetSyntax();
+ st.wordChars('\u0000', '\uffff');
+ st.quoteChar('\"');
+ st.quoteChar('\'');
+ st.whitespaceChars(' ', ' ');
+ st.whitespaceChars('\t', '\t');
+ st.whitespaceChars('\r', '\r');
+ st.whitespaceChars('\n', '\n');
+ while (st.nextToken() != StreamTokenizer.TT_EOF)
+ {
+ arguments.add(st.sval);
+ }
+ }
+ }
+
+ //--- Initialize Map for option parsing
+
+ initOptions();
+
+ //--- This will hold all options recognized by gjdoc itself
+ // and their associated arguments.
+ // Contains objects of type String[], where each entry
+ // specifies an option along with its aguments.
+
+ List options = new LinkedList();
+
+ //--- This will hold all command line tokens not recognized
+ // to be part of a standard option.
+ // These options are intended to be processed by the doclet
+ // Contains objects of type String, where each entry is
+ // one unrecognized token.
+
+ List customOptions = new LinkedList();
+
+ rootDoc = new RootDocImpl();
+ reporter = rootDoc.getReporter();
+
+ //--- Iterate over all options given on the command line
+
+ for (Iterator it = arguments.iterator(); it.hasNext();)
+ {
+
+ String arg = (String) it.next();
+
+ //--- Check if gjdoc recognizes this option as a standard option
+ // and remember the options' argument count
+
+ int optlen = optionLength(arg);
+
+ //--- Argument count == 0 indicates that the option is not recognized.
+ // Add it to the list of custom option tokens
+
+ //--- Otherwise the option is recognized as a standard option.
+ // if all required arguments are supplied. Create a new String
+ // array for the option and its arguments, and store it
+ // in the options array.
+
+ if (optlen > 0)
+ {
+ String[] option = new String[optlen];
+ option[0] = arg;
+ boolean optargs_ok = true;
+ for (int j = 1; j < optlen && optargs_ok; ++j)
+ {
+ if (it.hasNext())
+ {
+ option[j] = (String) it.next();
+ if (option[j].startsWith("-"))
+ {
+ optargs_ok = false;
+ }
+ }
+ else
+ {
+ optargs_ok = false;
+ }
+ }
+ if (optargs_ok)
+ options.add(option);
+ else
+ {
+ // If the option requires more arguments than given on the
+ // command line, issue a fatal error
+
+ reporter.printFatal("Missing value for option " + arg + ".");
+ }
+ }
+ }
+
+ //--- Create an array of String arrays from the dynamic array built above
+
+ String[][] optionArr = (String[][]) options.toArray(new String[options
+ .size()][0]);
+
+ //--- Validate all options and issue warnings/errors
+
+ if (validOptions(optionArr, rootDoc))
+ {
+
+ //--- We got valid options; parse them and store the parsed values
+ // in 'option_*' fields.
+
+ readOptions(optionArr);
+
+ //--- Show version and exit if requested by user
+
+ if (option_showVersion) {
+ System.out.println("gjdoc " + getGjdocVersion());
+ System.exit(0);
+ }
+
+ if (option_bootclasspath_specified) {
+ reporter.printWarning("-bootclasspath ignored: not supported by"
+ + " gjdoc wrapper script, or no wrapper script in use.");
+ }
+
+ // If we have an empty source path list, add the current directory ('.')
+
+ if (option_sourcepath.size() == 0)
+ option_sourcepath.add(new File("."));
+
+ //--- We have all information we need to start the doclet at this time
+
+ if (null != option_encoding) {
+ rootDoc.setSourceEncoding(option_encoding);
+ }
+ else {
+ // be quiet about this for now:
+ // reporter.printNotice("No encoding specified, using platform default: " + System.getProperty("file.encoding"));
+ rootDoc.setSourceEncoding(System.getProperty("file.encoding"));
+ }
+ rootDoc.setSourcePath(option_sourcepath);
+
+ //addJavaLangClasses();
+
+ if (!startDoclet(arguments)) {
+ return -1;
+ }
+ }
+
+ return reporter.getErrorCount();
+ }
+
+ private void addJavaLangClasses()
+ throws IOException
+ {
+ String resourceName = "/java.lang-classes-" + option_source + ".txt";
+ InputStream in = getClass().getResourceAsStream(resourceName);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = reader.readLine()) != null) {
+
+ String className = line.trim();
+ if (className.length() > 0) {
+ ClassDocImpl classDoc =
+ new ClassDocImpl(null, new PackageDocImpl("java.lang"),
+ ProgramElementDocImpl.ACCESS_PUBLIC,
+ false, false, null);
+ classDoc.setClass(className);
+ rootDoc.addClassDoc(classDoc);
+ }
+ }
+ }
+
+ /**
+ * Helper class for parsing command line arguments. An instance of this class
+ * represents a particular option accepted by gjdoc (e.g. '-sourcepath') along
+ * with the number of expected arguments and behavior to parse the arguments.
+ */
+ private abstract class OptionProcessor
+ {
+
+ /**
+ * Number of arguments expected by this option.
+ */
+ private int argCount;
+
+ /**
+ * Initializes this instance.
+ *
+ * @param argCount
+ * number of arguments
+ */
+ public OptionProcessor(int argCount)
+ {
+ this.argCount = argCount;
+ }
+
+ /**
+ * Overridden by derived classes with behavior to parse the arguments
+ * specified with this option.
+ *
+ * @param args
+ * command line arguments
+ */
+ abstract void process(String[] args);
+ }
+
+ /**
+ * Maps option tags (e.g. '-sourcepath') to OptionProcessor objects.
+ * Initialized only once by method initOptions(). FIXME: Rename to
+ * 'optionProcessors'.
+ */
+ private static Map options = null;
+
+ /**
+ * Initialize all OptionProcessor objects needed to scan/parse command line
+ * options. This cannot be done in a static initializer block because
+ * OptionProcessors need access to the Singleton instance of the Main class.
+ */
+ private void initOptions()
+ {
+
+ options = new HashMap();
+
+ //--- Put one OptionProcessor object into the map
+ // for each option recognized.
+
+ options.put("-overview", new OptionProcessor(2)
+ {
+
+ void process(String[] args)
+ {
+ option_overview = args[0];
+ }
+ });
+ options.put("-public", new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ option_coverage = COVERAGE_PUBLIC;
+ }
+ });
+ options.put("-protected", new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ option_coverage = COVERAGE_PROTECTED;
+ }
+ });
+ options.put("-package", new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ option_coverage = COVERAGE_PACKAGE;
+ }
+ });
+ options.put("-private", new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ option_coverage = COVERAGE_PRIVATE;
+ }
+ });
+ OptionProcessor helpProcessor = new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ option_help = true;
+ }
+ };
+
+ options.put("-help", helpProcessor);
+ options.put("--help", helpProcessor);
+ options.put("-doclet", new OptionProcessor(2)
+ {
+
+ void process(String[] args)
+ {
+ option_doclet = args[0];
+ }
+ });
+ options.put("-docletpath", new OptionProcessor(2)
+ {
+
+ void process(String[] args)
+ {
+ option_docletpath = args[0];
+ }
+ });
+ options.put("-nowarn", new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ option_nowarn = true;
+ }
+ });
+ options.put("-source", new OptionProcessor(2)
+ {
+
+ void process(String[] args)
+ {
+ option_source = args[0];
+ if (!"1.2".equals(option_source)
+ && !"1.3".equals(option_source)
+ && !"1.4".equals(option_source)) {
+
+ throw new RuntimeException("Only he following values are currently"
+ + " supported for option -source: 1.2, 1.3, 1.4.");
+ }
+ }
+ });
+ OptionProcessor sourcePathProcessor = new OptionProcessor(2) {
+ void process(String[] args)
+ {
+ Debug.log(1, "-sourcepath is '" + args[0] + "'");
+ for (StringTokenizer st = new StringTokenizer(args[0],
+ File.pathSeparator); st.hasMoreTokens();)
+ {
+ String path = st.nextToken();
+ File file = new File(path);
+ if (!(file.exists()))
+ {
+ throw new RuntimeException("The source path " + path
+ + " does not exist.");
+ }
+ option_sourcepath.add(file);
+ }
+ }
+ };
+ options.put("-s", sourcePathProcessor);
+ options.put("-sourcepath", sourcePathProcessor);
+ options.put("-subpackages", new OptionProcessor(2)
+ {
+ void process(String[] args)
+ {
+ StringTokenizer st = new StringTokenizer(args[0], ":");
+ while (st.hasMoreTokens()) {
+ String packageName = st.nextToken();
+
+ if (packageName.startsWith(".")
+ || packageName.endsWith(".")
+ || packageName.indexOf("..") > 0
+ || !checkCharSet(packageName,
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) {
+ throw new RuntimeException("Illegal package name '"
+ + packageName + "'");
+ }
+ option_subpackages.add(packageName);
+ }
+ }
+ });
+ options.put("-exclude", new OptionProcessor(2)
+ {
+ void process(String[] args)
+ {
+ StringTokenizer st = new StringTokenizer(args[0], ":");
+ while (st.hasMoreTokens()) {
+ String packageName = st.nextToken();
+
+ if (packageName.startsWith(".")
+ || packageName.endsWith(".")
+ || packageName.indexOf("..") > 0
+ || !checkCharSet(packageName,
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) {
+ throw new RuntimeException("Illegal package name '"
+ + packageName + "'");
+ }
+ option_exclude.add(packageName);
+ }
+ }
+ });
+ // TODO include other options here
+ options.put("-verbose", new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ option_verbose = true;
+ System.err.println("WARNING: Unsupported option -verbose ignored");
+ }
+ });
+ options.put("-quiet", new OptionProcessor(1)
+ {
+
+ void process(String[] args)
+ {
+ reporter.setQuiet(true);
+ }
+ });
+ options.put("-locale", new OptionProcessor(2)
+ {
+
+ void process(String[] args)
+ {
+ String localeName = args[0];
+ String language = null;
+ String country = null;
+ String variant = null;
+ StringTokenizer st = new StringTokenizer(localeName, "_");
+ if (st.hasMoreTokens()) {
+ language = st.nextToken();
+ }
+ if (st.hasMoreTokens()) {
+ country = st.nextToken();
+ }
+ if (st.hasMoreTokens()) {
+ variant = st.nextToken();
+ }
+ if (variant != null) {
+ option_locale = new Locale(language, country, variant);
+ }
+ else if (country != null) {
+ option_locale = new Locale(language, country);
+ }
+ else if (language != null) {
+ option_locale = new Locale(language);
+ }
+ else {
+ throw new RuntimeException("Illegal locale specification '"
+ + localeName + "'");
+ }
+ }
+ });
+ options.put("-encoding", new OptionProcessor(2)
+ {
+
+ void process(String[] args)
+ {
+ option_encoding = args[0];
+ }
+ });
+ options.put("-breakiterator", new OptionProcessor(1)
+ {
+ void process(String[] args)
+ {
+ option_breakiterator = true;
+ }
+ });
+ options.put("-licensetext", new OptionProcessor(1)
+ {
+ void process(String[] args)
+ {
+ option_licensetext = true;
+ }
+ });
+ options.put("-overview", new OptionProcessor(2)
+ {
+ void process(String[] args)
+ {
+ try {
+ getRootDoc().setRawCommentText(RootDocImpl.readHtmlBody(new File(args[0])));
+ }
+ catch (IOException e) {
+ throw new RuntimeException("Cannot read file specified in option -overview: " + e.getMessage());
+ }
+ }
+ });
+ options.put("-classpath", new OptionProcessor(2)
+ {
+ void process(String[] args)
+ {
+ reporter.printWarning("-classpath option could not be passed to the VM. Faking it with ");
+ reporter.printWarning(" System.setProperty(\"java.class.path\", \"" + args[0] + "\");");
+ System.setProperty("java.class.path", args[0]);
+ }
+ });
+ options.put("--version", new OptionProcessor(1)
+ {
+ void process(String[] args)
+ {
+ option_showVersion = true;
+ }
+ });
+ options.put("-bootclasspath", new OptionProcessor(1)
+ {
+ void process(String[] args)
+ {
+ option_bootclasspath_specified = true;
+ }
+ });
+ options.put("-all", new OptionProcessor(1)
+ {
+ void process(String[] args)
+ {
+ option_all = true;
+ }
+ });
+ options.put("-reflection", new OptionProcessor(1)
+ {
+ void process(String[] args)
+ {
+ option_reflection = true;
+ }
+ });
+ }
+
+ /**
+ * Determine how many arguments the given option requires.
+ *
+ * @param option
+ * The name of the option without leading dash.
+ */
+ private static int optionLength(String option)
+ {
+
+ OptionProcessor op = (OptionProcessor) options.get(option.toLowerCase());
+ if (op != null)
+ return op.argCount;
+ else
+ return 0;
+ }
+
+ /**
+ * Process all given options. Assumes that the options have been validated
+ * before.
+ *
+ * @param optionArr
+ * Each element is a series of Strings where [0] is the name of the
+ * option and [1..n] are the arguments to the option.
+ */
+ private void readOptions(String[][] optionArr)
+ {
+
+ //--- For each option, find the appropriate OptionProcessor
+ // and call its process() method
+
+ for (int i = 0; i < optionArr.length; ++i)
+ {
+ String[] opt = optionArr[i];
+ String[] args = new String[opt.length - 1];
+ System.arraycopy(opt, 1, args, 0, opt.length - 1);
+ OptionProcessor op = (OptionProcessor) options.get(opt[0].toLowerCase());
+ op.process(args);
+ }
+ }
+
+ /**
+ * Print command line usage.
+ */
+ private static void usage()
+ {
+ System.out
+ .print("\n"
+ + "USAGE: gjdoc [options] [packagenames] "
+ + "[sourcefiles] [@files]\n\n"
+ + " --version Show version information and exit\n"
+ + " -all Process all source files found in the source path\n"
+ + " -overview <file> Read overview documentation from HTML file\n"
+ + " -public Include only public classes and members\n"
+ + " -protected Include protected and public classes and members\n"
+ + " This is the default\n"
+ + " -package Include package/protected/public classes and members\n"
+ + " -private Include all classes and members\n"
+ + " -help, --help Show this information\n"
+ + " -doclet <class> Doclet class to use for generating output\n"
+ + " -docletpath <classpath> Specifies the search path for the doclet and\n"
+ + " dependencies\n"
+ + " -source <release> Provide source compatibility with specified\n"
+ + " release (1.4 to handle assertion)\n"
+ + " -sourcepath <pathlist> Where to look for source files\n"
+ + " -s <pathlist> Alias for -sourcepath\n"
+ + " -subpackages <spkglist> List of subpackages to recursively load\n"
+ + " -exclude <pkglist> List of packages to exclude\n"
+ + " -verbose Output messages about what Gjdoc is doing [ignored]\n"
+ + " -quiet Do not print non-error and non-warning messages\n"
+ + " -locale <name> Locale to be used, e.g. en_US or en_US_WIN\n"
+ + " -encoding <name> Source file encoding name\n"
+ + " -breakiterator Compute first sentence with BreakIterator\n"
+ + " -classpath <pathlist> Set the path used for loading auxilliary classes\n"
+ + "\n"
+ + "Standard doclet options:\n"
+ + " -d Set target directory\n"
+ + " -use Includes the 'Use' page for each documented class\n"
+ + " and package\n"
+ + " -version Includes the '@version' tag\n"
+ + " -author Includes the '@author' tag\n"
+ + " -splitindex Splits the index file into multiple files\n"
+ + " -windowtitle <text> Browser window title\n"
+ + " -doctitle <text> Title near the top of the overview summary file\n"
+ + " (HTML allowed)\n"
+ + " -title <text> Title for this set of API documentation\n"
+ + " (deprecated, -doctitle should be used instead)\n"
+ + " -header <text> Text to include in the top navigation bar\n"
+ + " (HTML allowed)\n"
+ + " -footer <text> Text to include in the bottom navigation bar\n"
+ + " (HTML allowed)\n"
+ + " -bottom <text> Text to include at the bottom of each output file\n"
+ + " (HTML allowed)\n"
+ + " -link <extdoc URL> Link to external generated documentation at URL\n"
+ + " -linkoffline <extdoc URL> <packagelistLoc>\n"
+ + " Link to external generated documentation for\n"
+ + " the specified package-list\n"
+ + " -linksource Creates an HTML version of each source file\n"
+ + " -group <groupheading> <packagepattern:packagepattern:...>\n"
+ + " Separates packages on the overview page into groups\n"
+ + " -nodeprecated Prevents the generation of any deprecated API\n"
+ + " -nodeprecatedlist Prevents the generation of the file containing\n"
+ + " the list of deprecated APIs and the link to the\n"
+ + " navigation bar to that page\n"
+ + " -nosince Omit the '@since' tag\n"
+ + " -notree Do not generate the class/interface hierarchy page\n"
+ + " -noindex Do not generate the index file\n"
+ + " -nohelp Do not generate the help link\n"
+ + " -nonavbar Do not generate the navbar, header and footer\n"
+ + " -helpfile <filen> Path to an alternate help file\n"
+ + " -stylesheetfile <file> Path to an alternate CSS stylesheet\n"
+ + " -addstylesheet <file> Path to an additional CSS stylesheet\n"
+ + " -serialwarn Complain about missing '@serial' tags [ignored]\n"
+ + " -charset <IANACharset> Specifies the HTML charset\n"
+ + " -docencoding <IANACharset>\n"
+ + " Specifies the encoding of the generated HTML files\n"
+ + " -tag <tagname>:Xaoptcmf:\"<taghead>\"\n"
+ + " Enables gjdoc to interpret a custom tag\n"
+ + " -taglet Adds a Taglet class to the map of taglets\n"
+ + " -tagletpath Sets the CLASSPATH to load subsequent Taglets from\n"
+ + " -docfilessubdirs Enables deep copy of 'doc-files' directories\n"
+ + " -excludedocfilessubdir <name1:name2:...>\n"
+ + " Excludes 'doc-files' subdirectories with a give name\n"
+ + " -noqualifier all|<packagename1:packagename2:...>\n"
+ + " Do never fully qualify given package names\n"
+ + " -nocomment Suppress the entire comment body including the main\n"
+ + " description and all tags, only generate declarations\n"
+ + "\n"
+ + "Gjdoc extension options:\n"
+ + " -reflection Use reflection for resolving unqualified class names\n"
+ + " -licensetext Include license text from source files\n"
+ + " -validhtml Use valid HTML/XML names (breaks compatibility)\n"
+ + " -baseurl <url> Hardwire the given base URL into generated pages\n"
+ /**
+ + " -genhtml Generate HTML code instead of XML code. This is the\n"
+ + " default.\n"
+ + " -geninfo Generate Info code instead of XML code.\n"
+ + " -xslsheet <file> If specified, XML files will be written to a\n"
+ + " temporary directory and transformed using the\n"
+ + " given XSL sheet. The result of the transformation\n"
+ + " is written to the output directory. Not required if\n"
+ + " -genhtml or -geninfo has been specified.\n"
+ + " -xmlonly Generate XML code only, do not generate HTML code.\n"
+ + " -bottomnote HTML code to include at the bottom of each page.\n"
+ + " -nofixhtml If not specified, heurestics will be applied to\n"
+ + " fix broken HTML code in comments.\n"
+ + " -nohtmlwarn Do not emit warnings when encountering broken HTML\n"
+ + " code.\n"
+ + " -noemailwarn Do not emit warnings when encountering strings like\n"
+ + " <abc@foo.com>.\n"
+ + " -indentstep <n> How many spaces to indent each tag level in\n"
+ + " generated XML code.\n"
+ + " -xsltdriver <class> Specifies the XSLT driver to use for transformation.\n"
+ + " By default, xsltproc is used.\n"
+ + " -postprocess <class> XmlDoclet postprocessor class to apply after XSL\n"
+ + " transformation.\n"
+ + " -compress Generated info pages will be Zip-compressed.\n"
+ + " -workpath Specify a temporary directory to use.\n"
+ + " -authormail <type> Specify handling of mail addresses in @author tags.\n"
+ + " no-replace do not replace mail addresses (default).\n"
+ + " mailto-name replace by <a>Real Name</a>.\n"
+ + " name-mailto-address replace by Real Name (<a>abc@foo.com</a>).\n"
+ + " name-mangled-address replace by Real Name (<a>abc AT foo DOT com</a>).\n"
+ **/
+ );
+ }
+
+ /**
+ * The root of the gjdoc tool.
+ *
+ * @return all the options of the gjdoc application.
+ */
+ public static RootDocImpl getRootDoc()
+ {
+ return rootDoc;
+ }
+
+ /**
+ * Get the gjdoc singleton.
+ *
+ * @return the gjdoc instance.
+ */
+ public static Main getInstance()
+ {
+ return instance;
+ }
+
+ /**
+ * Is this access level covered?
+ *
+ * @param accessLevel
+ * the access level we want to know if it is covered.
+ * @return true if the access level is covered.
+ */
+ public boolean includeAccessLevel(int accessLevel)
+ {
+ return coverageTemplates[option_coverage][accessLevel];
+ }
+
+ /**
+ * Is the doclet running?
+ *
+ * @return true if it's running
+ */
+ public boolean isDocletRunning()
+ {
+ return docletRunning;
+ }
+
+ /**
+ * Check the charset. Check that all the characters of the string 'toCheck'
+ * and query if they exist in the 'charSet'. The order does not matter. The
+ * number of times a character is in the variable does not matter.
+ *
+ * @param toCheck
+ * the charset to check.
+ * @param charSet
+ * the reference charset
+ * @return true if they match.
+ */
+ public static boolean checkCharSet(String toCheck, String charSet)
+ {
+ for (int i = 0; i < toCheck.length(); ++i)
+ {
+ if (charSet.indexOf(toCheck.charAt(i)) < 0)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Makes the RootDoc eligible for the GC.
+ */
+ public static void releaseRootDoc()
+ {
+ rootDoc.flush();
+ }
+
+ /**
+ * Return whether the -breakiterator option has been specified.
+ */
+ public boolean isUseBreakIterator()
+ {
+ return this.option_breakiterator
+ || !getLocale().getLanguage().equals(Locale.ENGLISH.getLanguage());
+ }
+
+ /**
+ * Return whether boilerplate license text should be copied.
+ */
+ public boolean isCopyLicenseText()
+ {
+ return this.option_licensetext;
+ }
+
+ /**
+ * Return the locale specified using the -locale option or the
+ * default locale;
+ */
+ public Locale getLocale()
+ {
+ return this.option_locale;
+ }
+
+ /**
+ * Return the collator to use based on the specified -locale
+ * option. If no collator can be found for the given locale, a
+ * warning is emitted and the default collator is used instead.
+ */
+ public Collator getCollator()
+ {
+ if (null == this.collator) {
+ Locale locale = getLocale();
+ this.collator = Collator.getInstance(locale);
+ Locale defaultLocale = Locale.getDefault();
+ if (null == this.collator
+ && !defaultLocale.equals(locale)) {
+ this.collator = Collator.getInstance(defaultLocale);
+ if (null != this.collator) {
+ reporter.printWarning("No collator found for locale "
+ + locale.getDisplayName()
+ + "; using collator for default locale "
+ + defaultLocale.getDisplayName()
+ + ".");
+ }
+ else {
+ this.collator = Collator.getInstance();
+ reporter.printWarning("No collator found for specified locale "
+ + locale.getDisplayName()
+ + " or default locale "
+ + defaultLocale.getDisplayName()
+ + ": using default collator.");
+ }
+ }
+ if (null == this.collator) {
+ this.collator = Collator.getInstance();
+ reporter.printWarning("No collator found for locale "
+ + locale.getDisplayName()
+ + ": using default collator.");
+ }
+ }
+ return this.collator;
+ }
+
+ public boolean isCacheRawComments()
+ {
+ return true;
+ }
+
+ public String getGjdocVersion()
+ {
+ if (null == gjdocVersion) {
+ gjdocVersion = gnu.classpath.Configuration.CLASSPATH_VERSION;
+ }
+ return gjdocVersion;
+ }
+
+ public boolean isReflectionEnabled()
+ {
+ return this.option_reflection;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/MemberDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/MemberDocImpl.java
new file mode 100644
index 000000000..acc812863
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/MemberDocImpl.java
@@ -0,0 +1,235 @@
+/* gnu.classpath.tools.gjdoc.MemberDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.util.*;
+import com.sun.javadoc.*;
+
+public abstract class MemberDocImpl extends ProgramElementDocImpl implements MemberDoc {
+
+ protected String typeName;
+ protected Type type;
+
+ public MemberDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ SourcePosition position) {
+
+ super(containingClass,
+ containingPackage,
+ position);
+ }
+
+ public String qualifiedName() {
+ return containingClass().qualifiedName()+"."+name();
+ }
+
+ public boolean isSynthetic() {
+ return false;
+ }
+
+ int parseModifiers(char[] source, int startIndex, int endIndex) {
+
+ Debug.log(9,"parseModifiers '"+new String(source,startIndex,endIndex-startIndex)+"'");
+
+ final int STATE_NORMAL = 1;
+ final int STATE_STARC = 2;
+ final int STATE_SLASHC = 3;
+
+ int state = STATE_NORMAL;
+
+ StringBuffer word = new StringBuffer();
+ StringBuffer typeNameBuf = new StringBuffer();
+ int lastWordStart = startIndex;
+ int firstChar = 0;
+ int lastChar = 0;
+ for (; startIndex<endIndex; ++startIndex) {
+ if (state==STATE_STARC) {
+ if (startIndex<endIndex-1 && source[startIndex]=='*' && source[startIndex+1]=='/') {
+ ++startIndex;
+ state=STATE_NORMAL;
+ }
+ }
+ else if (state==STATE_SLASHC) {
+ if (source[startIndex]=='\n') {
+ state=STATE_NORMAL;
+ }
+ }
+ else if (startIndex<endIndex-1 && source[startIndex]=='/' && source[startIndex+1]=='*') {
+ ++startIndex;
+ state=STATE_STARC;
+ }
+ else if (source[startIndex]=='=' || source[startIndex]=='(' || source[startIndex]==';') {
+ typeName = typeNameBuf.toString();
+ return lastWordStart;
+ }
+ else if (Parser.WHITESPACE.indexOf(source[startIndex])>=0
+ || (startIndex > 0 && source[startIndex-1] == ']' && source[startIndex] != '[')) {
+ if (word.length()>0 && lastChar != '.') {
+ if (processModifier(word.toString())) {
+ }
+ else if (typeNameBuf.length()==0 && !isConstructor()) {
+ typeNameBuf.setLength(0);
+ typeNameBuf.append(word);
+ }
+ else if ((firstChar=='[' || firstChar==']') && !isConstructor()) {
+ typeNameBuf.append(word);
+ }
+ else {
+ typeName = typeNameBuf.toString();
+ return lastWordStart;
+ }
+ word.setLength(0);
+ lastWordStart=startIndex;
+ }
+ }
+ else {
+ if (lastWordStart<0) lastWordStart=startIndex;
+ lastChar = source[startIndex];
+ if (0 == word.length()) {
+ firstChar = lastChar;
+ }
+ word.append((char)lastChar);
+ }
+ }
+
+ typeName = typeNameBuf.toString();
+ return startIndex;
+ }
+
+ public Type type() {
+ //public Type type() throws ParseException {
+ Debug.log(9,"type() called on "+containingClass()+"."+this);
+ if (type==null) {
+ try {
+ type=((ClassDocImpl)containingClass()).typeForString(typeName);
+ } catch (ParseException e) {
+ System.err.println("FIXME: add try-catch to force compilation");
+ e.printStackTrace();
+ }
+ }
+ return type;
+ }
+
+
+ protected void setName(String name) {
+ this.name=name;
+ }
+ private String name;
+
+
+ public String name() {
+ return name;
+ }
+
+ public void setTypeName(String typeName) {
+ this.typeName=typeName;
+ this.type=null;
+ }
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ // return true if this Doc is include in the active set.
+ public boolean isIncluded() {
+ return Main.getInstance().includeAccessLevel(accessLevel);
+ }
+
+ public int compareTo(Object o) {
+ if (o instanceof MemberDocImpl) {
+ int rc=name().compareTo(((MemberDocImpl)o).name());
+ if (rc==0)
+ rc=containingClass().qualifiedName().compareTo(((MemberDocImpl)o).containingClass().qualifiedName());
+ return rc;
+ }
+ else {
+ return super.compareTo(o);
+ }
+ }
+
+ void resolve() {
+
+ if (type==null && typeName!=null) {
+ Debug.log(1, "MemberDocImpl.resolve(), looking up type named "+typeName);
+ try {
+ type=((ClassDocImpl)containingClass()).typeForString(typeName);
+ } catch (ParseException e) {
+ //System.err.println("FIXME: add try-catch to force compilation");
+ //e.printStackTrace();
+ Debug.log(1, "INTERNAL WARNING: Couldn't find type for name '"+typeName+"'");
+ }
+ }
+
+ if (type instanceof ClassDocProxy) {
+ String className=type.qualifiedTypeName();
+ ClassDoc realClassDoc=((ClassDocImpl)containingClass()).findClass(className, type.dimension());
+ if (realClassDoc!=null) {
+ type=realClassDoc;
+ }
+ else {
+ //throw new Error("Class not found: "+className);
+ /*** This is not an error, the class was not included
+ * on the command line. Perhaps emit a notice here.
+ *
+
+ Main.getRootDoc().printError("Class not found '"
+ + className
+ + "' in class '"
+ + containingClass().qualifiedName()
+ + "' member '"
+ + name()
+ + "'");
+ */
+ }
+ }
+ }
+
+ public void resolveComments()
+ {
+ super.resolveComments();
+
+ if (tagMap.isEmpty()) {
+ TagContainer inheritedTagMap = ClassDocImpl.findInheritedDoc(containingClass(),
+ this,
+ null);
+ if (null != inheritedTagMap) {
+ this.tagMap = inheritedTagMap.getTagMap();
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/MethodDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/MethodDocImpl.java
new file mode 100644
index 000000000..78748c848
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/MethodDocImpl.java
@@ -0,0 +1,64 @@
+/* gnu.classpath.tools.gjdoc.MethodDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.util.*;
+import com.sun.javadoc.*;
+
+public class MethodDocImpl extends ExecutableMemberDocImpl implements MethodDoc {
+
+ public MethodDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ SourcePosition position) {
+
+ super(containingClass,
+ containingPackage,
+ position);
+ }
+
+ // Is this Doc item a class.
+ public boolean isMethod() {
+ return true;
+ }
+
+ public Type returnType() {
+ return super.type();
+ }
+
+ public String toString() { return name()+((signature()==null)?"()":signature()); }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/PackageDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/PackageDocImpl.java
new file mode 100644
index 000000000..84960bcf3
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/PackageDocImpl.java
@@ -0,0 +1,223 @@
+/* gnu.classpath.tools.gjdoc.PackageDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.io.File;
+
+class PackageDocImpl extends DocImpl implements GjdocPackageDoc {
+
+ private String packageName;
+ private File packageDirectory;
+
+ private Set allClassesSet = new TreeSet();
+ private List ordinaryClassesList = new ArrayList();
+ private List exceptionsList = new ArrayList();
+ private List interfacesList = new ArrayList();
+ private List errorsList = new ArrayList();
+
+ private ClassDoc[] allClasses;
+ private ClassDoc[] ordinaryClasses;
+ private ClassDoc[] exceptions;
+ private ClassDoc[] interfaces;
+ private ClassDoc[] errors;
+
+ PackageDocImpl(String packageName) {
+ super(null);
+ this.packageName=packageName;
+ }
+
+ public void addClass(ClassDoc classDoc) {
+ if (Main.getInstance().includeAccessLevel(((ClassDocImpl)classDoc).accessLevel)) {
+ allClassesSet.add(classDoc);
+ }
+ }
+
+ public void resolve() {
+ for (Iterator it=allClassesSet.iterator(); it.hasNext(); ) {
+ ClassDocImpl classDoc=(ClassDocImpl)it.next();
+ try {
+ classDoc.resolve();
+ } catch (ParseException e) {
+ System.err.println("FIXME: add try-catch to force compilation"
+ + e);
+ }
+
+ if (classDoc.isInterface()) {
+ interfacesList.add(classDoc);
+ }
+ else if (classDoc.isException()) {
+ exceptionsList.add(classDoc);
+ }
+ else if (classDoc.isError()) {
+ errorsList.add(classDoc);
+ }
+ else {
+ ordinaryClassesList.add(classDoc);
+ }
+ }
+ }
+
+ public void resolveComments() {
+ if (rawDocumentation!=null) {
+ this.tagMap=parseCommentTags(rawDocumentation.toCharArray(),
+ 0,
+ rawDocumentation.length(),
+ null,
+ null,
+ null,
+ null);
+ }
+
+ resolveTags();
+ }
+
+ public String name() {
+ return packageName;
+ }
+
+ public ClassDoc[] allClasses()
+ {
+ if (null == this.allClasses) {
+ this.allClasses = toClassDocArray(allClassesSet);
+ }
+ return this.allClasses;
+ }
+
+ public ClassDoc[] ordinaryClasses()
+ {
+ if (null == this.ordinaryClasses) {
+ this.ordinaryClasses = toClassDocArray(ordinaryClassesList);
+ }
+ return this.ordinaryClasses;
+ }
+
+
+ public ClassDoc[] exceptions()
+ {
+ if (null == this.exceptions) {
+ this.exceptions = toClassDocArray(exceptionsList);
+ }
+ return this.exceptions;
+ }
+
+ public ClassDoc[] interfaces()
+ {
+ if (null == this.interfaces) {
+ this.interfaces = toClassDocArray(interfacesList);
+ }
+ return this.interfaces;
+ }
+
+ public ClassDoc[] errors()
+ {
+ if (null == this.errors) {
+ this.errors = toClassDocArray(errorsList);
+ }
+ return this.errors;
+ }
+
+ private ClassDoc[] toClassDocArray(Collection classDocList)
+ {
+ ClassDoc[] result = (ClassDoc[])classDocList.toArray(new ClassDoc[classDocList.size()]);
+ Arrays.sort(result);
+ return result;
+ }
+
+ public ClassDoc findClass(String name) {
+ return Main.getRootDoc().classNamed(packageName+"."+name);
+ }
+
+ public void dump(int level) {
+ Debug.log(level, "All classes:");
+ Debug.dumpArray(level, allClasses());
+
+ Debug.log(level, "Ordinary classes:");
+ Debug.dumpArray(level, ordinaryClasses());
+
+ }
+
+ public static final PackageDocImpl DEFAULT_PACKAGE = new PackageDocImpl("");
+
+ public boolean isPackage() {
+ return true;
+ }
+
+ public boolean isIncluded() {
+ return isIncluded;
+ }
+
+ void setIsIncluded(boolean b) {
+ this.isIncluded=b;
+ }
+
+ private boolean isIncluded = false;
+
+ public String toString() {
+ return packageName;
+ }
+
+ public int compareTo(Object o) {
+ if (o!=null && o instanceof PackageDocImpl)
+ return name().compareTo(((PackageDocImpl)o).name());
+ else
+ return 0;
+ }
+
+ public boolean equals(Object o) {
+ if (o!=null && o instanceof PackageDocImpl)
+ return name().equals(((PackageDocImpl)o).name());
+ else
+ return false;
+ }
+
+ /**
+ * Sets the directory containing this package's source files.
+ */
+ public void setPackageDirectory(File packageDirectory) {
+ this.packageDirectory = packageDirectory;
+ }
+
+ /**
+ * Gets the directory containing this package's source files.
+ */
+ public File packageDirectory() {
+ return this.packageDirectory;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParamTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParamTagImpl.java
new file mode 100644
index 000000000..a7491dc8e
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParamTagImpl.java
@@ -0,0 +1,81 @@
+/* gnu.classpath.tools.gjdoc.ParamTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+
+public class ParamTagImpl extends AbstractTagImpl implements ParamTag {
+
+ private String parameterName;
+ private String parameterComment;
+
+ public ParamTagImpl(String text,
+ ClassDocImpl contextClass,
+ MemberDocImpl contextMember) {
+ super(text);
+ char[] textarr=text.toCharArray();
+ int i=0;
+ for (; i<textarr.length; ++i) {
+ if (!Parser.isWhitespace(textarr[i])) break;
+ }
+ for (; i<textarr.length; ++i) {
+ if (Parser.isWhitespace(textarr[i])) {
+ parameterName=new String(textarr,0,i).trim();
+ parameterComment=new String(textarr,i,textarr.length-i).trim();
+ break;
+ }
+ }
+ if (parameterComment!=null) {
+ setBody(parameterComment, contextClass, contextMember);
+ }
+ }
+
+ public String parameterComment() {
+ return parameterComment;
+ }
+
+ public String parameterName() {
+ return parameterName;
+ }
+
+ public String kind() {
+ return "@param";
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParameterImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParameterImpl.java
new file mode 100644
index 000000000..29b8e9b70
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParameterImpl.java
@@ -0,0 +1,69 @@
+/* gnu.classpath.tools.gjdoc.ParameterImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+
+public class ParameterImpl implements Parameter {
+
+ String name;
+ String typeName;
+ Type type;
+
+ ParameterImpl(String name, String typeName, Type type) {
+
+ this.name=name;
+ this.typeName=typeName;
+ this.type=type;
+ }
+
+ public void resolve(ClassDoc classContext) {
+ if (type instanceof ClassDocProxy) {
+ String className=type.qualifiedTypeName();
+ ClassDoc realClassDoc=((ClassDocImpl)classContext).findClass(className, type.dimension());
+ if (realClassDoc!=null) {
+ type=realClassDoc;
+ }
+ }
+ }
+
+ public String name() { return name; }
+ public String typeName() { return typeName; }
+ public Type type() { return type; }
+ public String toString() { return typeName+" "+name; }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParseException.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParseException.java
new file mode 100644
index 000000000..3ecd84592
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ParseException.java
@@ -0,0 +1,51 @@
+/* gnu.classpath.tools.gjdoc.ParseException
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+class ParseException extends Exception {
+
+ public ParseException()
+ {
+ }
+
+ public ParseException(String msg)
+ {
+ super(msg);
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Parser.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Parser.java
new file mode 100644
index 000000000..d355b5384
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Parser.java
@@ -0,0 +1,1064 @@
+/* gnu.classpath.tools.gjdoc.Parser
+ Copyright (C) 2001, 2005, 2008 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.util.*;
+
+import com.sun.javadoc.*;
+
+import gnu.classpath.tools.IOToolkit;
+import gnu.classpath.tools.NotifyingInputStreamReader;
+import gnu.classpath.tools.MalformedInputListener;
+import gnu.classpath.tools.MalformedInputEvent;
+
+ class IgnoredFileParseException extends ParseException
+ {
+ // marker exception
+ }
+
+ abstract class SourceComponent {
+
+ abstract int match(char[] source, int index) throws ParseException;
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) throws ParseException, IOException {
+ return endIndex;
+ }
+
+ int getEndIndex(char[] source, int endIndex) throws ParseException {
+ return endIndex;
+ }
+ }
+
+ abstract class BlockSourceComponent extends SourceComponent {
+
+ int getEndIndex(char[] source, int endIndex) throws ParseException {
+ return Parser.skipExpression(source, endIndex, 1, '\0');
+ }
+
+ }
+
+ class Whitespace extends SourceComponent {
+
+ int match(char[] source, int index) {
+
+ int rc=index;
+ int slen=source.length;
+ while (rc<slen && Parser.WHITESPACE.indexOf(source[rc])>=0) ++rc;
+
+ return (rc!=index) ? rc : -1;
+ }
+ }
+
+ class BracketClose extends SourceComponent {
+
+ int match(char[] source, int index) {
+ if (source[index]=='}') {
+ return index+1;
+ }
+ else {
+ return -1;
+ }
+ }
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex)
+ throws ParseException, IOException
+ {
+ parser.classClosed();
+ return endIndex;
+ }
+ }
+
+ class CommentComponent extends SourceComponent {
+
+ int match(char[] source, int index) throws ParseException {
+ if (index+1<source.length && source[index]=='/' && source[index+1]=='*') {
+ for (index+=2; index+1<source.length; ++index) {
+ if (source[index]=='*' && source[index+1]=='/')
+ return index+2;
+ }
+ throw new ParseException("unexpected end of input");
+ }
+ return -1;
+ }
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) {
+
+ if (source[startIndex+0]=='/'
+ && source[startIndex+1]=='*'
+ && source[startIndex+2]=='*') {
+
+ parser.setLastComment(new String(source, startIndex, endIndex-startIndex));
+ }
+ else if (null == parser.getBoilerplateComment() && Main.getInstance().isCopyLicenseText()) {
+ String boilerplateComment = new String(source, startIndex + 2, endIndex-startIndex - 4);
+ if (boilerplateComment.toLowerCase().indexOf("copyright") >= 0) {
+ parser.setBoilerplateComment(boilerplateComment);
+ }
+ }
+
+ return endIndex;
+ }
+ }
+
+ class SlashSlashCommentComponent extends SourceComponent {
+
+ int match(char[] source, int index) {
+ if (index+1<source.length && source[index]=='/' && source[index+1]=='/') {
+ index+=2;
+ while (index<source.length && source[index]!='\n')
+ ++index;
+ return index;
+ }
+ else {
+ return -1;
+ }
+ }
+ }
+
+ class EmptyStatementComponent extends SourceComponent {
+
+ int match(char[] source, int index) {
+ while (index < source.length
+ && Parser.isWhitespace(source[index])) {
+ ++ index;
+ }
+ if (index < source.length && source[index] == ';') {
+ return index+1;
+ }
+ else {
+ return -1;
+ }
+ }
+ }
+
+ class ImportComponent extends SourceComponent {
+
+ int match(char[] source, int index) {
+ if (index+7<source.length) {
+ if (source[index+0]=='i'
+ && source[index+1]=='m'
+ && source[index+2]=='p'
+ && source[index+3]=='o'
+ && source[index+4]=='r'
+ && source[index+5]=='t'
+ && Parser.WHITESPACE.indexOf(source[index+6])>=0) {
+
+ for (index+=7; index<source.length && source[index]!=';'; ++index)
+ ;
+
+ return index+1;
+ }
+ }
+ return -1;
+ }
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) throws ParseException, IOException {
+ String importString=new String(source,startIndex+7,endIndex-startIndex-7-1).trim();
+ parser.importEncountered(importString);
+ return endIndex;
+ }
+ }
+
+ class PackageComponent extends SourceComponent {
+
+ int match(char[] source, int index) {
+ if (index+10<source.length) {
+ if (source[index+0]=='p'
+ && source[index+1]=='a'
+ && source[index+2]=='c'
+ && source[index+3]=='k'
+ && source[index+4]=='a'
+ && source[index+5]=='g'
+ && source[index+6]=='e'
+ && Parser.WHITESPACE.indexOf(source[index+7])>=0) {
+
+ for (index+=7; index<source.length && source[index]!=';'; ++index)
+ ;
+
+ return index+1;
+ }
+ }
+ return -1;
+ }
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) {
+ String packageName=new String(source,startIndex+8,endIndex-startIndex-8-1).trim();
+ parser.packageOpened(packageName);
+ return endIndex;
+ }
+ }
+
+ class FieldComponent extends SourceComponent {
+
+ int match(char[] source, int index) throws ParseException {
+ boolean isField=false;
+ final int STATE_NORMAL=1;
+ final int STATE_SLASHC=2;
+ final int STATE_STARC=3;
+ final int STATE_FIELDVAL=4;
+ final int STATE_STRING=5;
+ final int STATE_SINGLEQUOTED=6;
+ final int STATE_STRING_BS=7;
+ final int STATE_SINGLEQUOTED_BS=8;
+
+ int state=STATE_NORMAL;
+ int prevState=STATE_NORMAL;
+
+ int fieldValueLevel = 0;
+
+ for (; index<source.length && !isField; ++index) {
+ if (state==STATE_STARC) {
+ if (index<source.length-1 && source[index]=='*' && source[index+1]=='/') {
+ ++index;
+ state=prevState;
+ }
+ }
+ else if (state==STATE_SLASHC) {
+ if (source[index]=='\n') {
+ state=prevState;
+ }
+ }
+ else if (state==STATE_STRING) {
+ if (source[index]=='\\') {
+ state=STATE_STRING_BS;
+ }
+ else if (source[index]=='\"') {
+ state=prevState;
+ }
+ }
+ else if (state==STATE_STRING_BS) {
+ state=STATE_STRING;
+ }
+ else if (state==STATE_SINGLEQUOTED) {
+ if (source[index]=='\\') {
+ state=STATE_SINGLEQUOTED_BS;
+ }
+ else if (source[index]=='\'') {
+ state=prevState;
+ }
+ }
+ else if (state==STATE_SINGLEQUOTED_BS) {
+ state=STATE_SINGLEQUOTED;
+ }
+ else if (state==STATE_FIELDVAL) {
+ if (source[index]=='/') {
+ if (index<source.length-1 && source[index+1]=='*') {
+ state=STATE_STARC;
+ ++index;
+ }
+ else if (index<source.length-1 && source[index+1]=='/') {
+ state=STATE_SLASHC;
+ ++index;
+ }
+ }
+ else if (source[index]=='{') {
+ ++ fieldValueLevel;
+ }
+ else if (source[index]=='}') {
+ -- fieldValueLevel;
+ }
+ else if (source[index]=='\"') {
+ state=STATE_STRING;
+ }
+ else if (source[index]=='\'') {
+ state=STATE_SINGLEQUOTED;
+ }
+ else if (source[index]==';' && 0 == fieldValueLevel) {
+ isField=true;
+ break;
+ }
+ }
+ else switch (source[index]) {
+ case '/':
+ if (index<source.length-1 && source[index+1]=='*') {
+ state=STATE_STARC;
+ ++index;
+ }
+ else if (index<source.length-1 && source[index+1]=='/') {
+ state=STATE_SLASHC;
+ ++index;
+ }
+ break;
+ case '{': // class
+ case '(': // method
+ return -1;
+ case '=': // field
+ state=STATE_FIELDVAL;
+ prevState=state;
+ continue;
+ case ';': // field
+ isField=true;
+ break;
+ }
+ if (isField) break;
+ }
+ if (!isField || index==source.length) {
+ return -1;
+ }
+
+ //System.err.println("char is "+source[index]);
+
+ if (source[index]!=';') {
+ index=Parser.skipExpression(source, index, 0, ';');
+ }
+ return index+1;
+ }
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) {
+
+ //Debug.log(9,"found package statement: \""+str+"\"");
+ //Debug.log(9,"found function component: '"+str+"'");
+ //xxx(new FieldDocImpl(ctx.classDoc, ctx.classDoc.containingPackage(), 0, false, false));
+
+ // Ignore superfluous semicoli after class definition
+ if (endIndex-startIndex<=1) return endIndex;
+
+ //assert (parser.ctx!=null);
+ Collection fields=FieldDocImpl.createFromSource(parser.ctx.classDoc,
+ parser.ctx.classDoc.containingPackage(),
+ source, startIndex, endIndex);
+
+ for (Iterator it=fields.iterator(); it.hasNext(); ) {
+ FieldDocImpl field=(FieldDocImpl)it.next();
+ boolean fieldHasSerialTag=!field.isTransient() && !field.isStatic(); //field.hasSerialTag();
+ if ((field.isIncluded() || fieldHasSerialTag) && parser.getAddComments()) {
+ field.setRawCommentText(parser.getLastComment());
+ }
+ parser.ctx.fieldList.add(field);
+ if (field.isIncluded()) {
+ parser.ctx.filteredFieldList.add(field);
+ }
+ if (fieldHasSerialTag) {
+ parser.ctx.sfieldList.add(field);
+ }
+ }
+
+ parser.setLastComment(null);
+ return endIndex;
+ }
+
+
+ }
+
+ class FunctionComponent extends BlockSourceComponent {
+
+ int getEndIndex(char[] source, int endIndex) throws ParseException {
+ if (source[endIndex-1]==';') {
+ return endIndex;
+ }
+ else {
+ return super.getEndIndex(source, endIndex);
+ }
+ }
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) throws IOException, ParseException {
+
+ //ctx.fieldList.add(FieldDocImpl.createFromSource(source, startIndex, endIndex));
+
+ //System.out.println("function match '"+new String(source,startIndex,endIndex-startIndex)+"'");
+ ExecutableMemberDocImpl execDoc=MethodDocImpl.createFromSource(parser.ctx.classDoc,
+ parser.ctx.classDoc.containingPackage(),
+ source, startIndex, endIndex);
+
+ if (parser.getAddComments())
+ execDoc.setRawCommentText(parser.getLastComment());
+
+ parser.setLastComment(null);
+
+ if (execDoc.isMethod()) {
+ parser.ctx.methodList.add(execDoc);
+ if (execDoc.isIncluded()) {
+ parser.ctx.filteredMethodList.add(execDoc);
+ }
+ }
+ else {
+ parser.ctx.constructorList.add(execDoc);
+ if (execDoc.isIncluded()) {
+ parser.ctx.filteredConstructorList.add(execDoc);
+ }
+ }
+
+ if (execDoc.isMethod()
+ && (execDoc.name().equals("readObject")
+ || execDoc.name().equals("writeObject")
+ || execDoc.name().equals("readExternal")
+ || execDoc.name().equals("writeExternal")
+ || execDoc.name().equals("readResolve"))) {
+ // FIXME: add readExternal here?
+
+ parser.ctx.maybeSerMethodList.add(execDoc);
+ }
+
+ return endIndex;
+ }
+
+ int match(char[] source, int index) {
+ boolean isFunc=false;
+ final int STATE_NORMAL=1;
+ final int STATE_SLASHC=2;
+ final int STATE_STARC=3;
+ int state=STATE_NORMAL;
+ for (; index<source.length && !isFunc; ++index) {
+ if (state==STATE_STARC) {
+ if (source[index]=='*' && source[index+1]=='/') {
+ ++index;
+ state=STATE_NORMAL;
+ }
+ }
+ else if (state==STATE_SLASHC) {
+ if (source[index]=='\n') {
+ state=STATE_NORMAL;
+ }
+ }
+ else switch (source[index]) {
+ case '/':
+ if (source[index+1]=='*') {
+ state=STATE_STARC;
+ ++index;
+ }
+ else if (source[index+1]=='/') {
+ state=STATE_SLASHC;
+ ++index;
+ }
+ break;
+ case '=': // field
+ case ';': // field
+ case '{': // class
+ return -1;
+ case '(':
+ isFunc=true;
+ break;
+ }
+ if (isFunc) break;
+ }
+ if (!isFunc || index==source.length)
+ return -1;
+
+ for (; index<source.length && (state!=STATE_NORMAL || (source[index]!='{' && source[index]!=';')); ++index)
+ if (state==STATE_SLASHC && source[index]=='\n') {
+ state=STATE_NORMAL;
+ }
+ else if (index<source.length-1) {
+ if (state==STATE_STARC) {
+ if (source[index]=='*' && source[index+1]=='/') {
+ state=STATE_NORMAL;
+ }
+ }
+ else {
+ if (source[index]=='/' && source[index+1]=='*') {
+ state=STATE_STARC;
+ }
+ else if (source[index]=='/' && source[index+1]=='/') {
+ state=STATE_SLASHC;
+ }
+ }
+ }
+ return index+1;
+ }
+
+
+ }
+
+ class StaticBlockComponent extends BlockSourceComponent {
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) {
+ //Debug.log(9,"found package statement: \""+str+"\"");
+ //Debug.log(9,"found function component: '"+str+"'");
+ parser.setLastComment(null);
+ return endIndex;
+ }
+
+ int match(char[] source, int index) {
+ if (source[index]=='{') return index+1;
+
+ if (index+7<source.length) {
+ if (source[index+0]=='s'
+ && source[index+1]=='t'
+ && source[index+2]=='a'
+ && source[index+3]=='t'
+ && source[index+4]=='i'
+ && source[index+5]=='c') {
+
+ for (index+=6; index<source.length && Parser.WHITESPACE.indexOf(source[index])>=0; ++index)
+ ;
+
+ if (index<source.length && source[index]=='{')
+ return index+1;
+ else
+ return -1;
+ }
+ }
+ return -1;
+ }
+
+ }
+
+ class ClassComponent extends SourceComponent {
+
+ int match(char[] source, int index) {
+ boolean isClass=false;
+ for (; index<source.length && !isClass; ++index) {
+ switch (source[index]) {
+ case '/': // possible comment
+ if (index<source.length-1) {
+ char c = source[index+1];
+ if ('/' == c) {
+ index += 2;
+ while (index<source.length && source[index]!=10) {
+ ++ index;
+ }
+ }
+ else if ('*' == c) {
+ index += 3;
+ while (index<source.length && (source[index-1] != '*' || source[index]!='/')) {
+ ++ index;
+ }
+ }
+ }
+ break;
+ case '@': // annotation
+ index += 1;
+ while(index<source.length && Character.isJavaIdentifierPart(source[index])) {
+ ++ index;
+ }
+ if (index<source.length && source[index]=='(') {
+ int parLevel = 1;
+ index += 1;
+ while (index<source.length && parLevel>0) {
+ if (source[index] == '(')
+ ++ parLevel;
+ if (source[index] == ')')
+ -- parLevel;
+ ++ index;
+ if (parLevel==0)
+ break;
+ }
+ }
+ break;
+ case '=': // field
+ case ';': // field
+ case '(': // function
+ return -1;
+ case '{':
+ isClass=true;
+ break;
+ }
+ if (isClass) break;
+ }
+ if (!isClass || index>=source.length)
+ return -1;
+
+ return index+1;
+ }
+
+ int process(Parser parser, char[] source, int startIndex, int endIndex) throws ParseException, IOException {
+
+ parser.classOpened(source, startIndex, endIndex);
+ if (parser.getAddComments())
+ parser.ctx.classDoc.setRawCommentText(parser.getLastComment());
+ parser.setLastComment(null);
+ if (parser.ctx.classDoc.isEnum())
+ {
+ int depth = 0;
+ for (int a = endIndex; a < source.length; ++a)
+ {
+ Debug.log(9, "Enum skipping " + a);
+ if (source[a] == '{')
+ {
+ Debug.log(1, "Found inner { in enum");
+ ++depth;
+ }
+ if (source[a] == '}')
+ {
+ if (depth > 0)
+ {
+ Debug.log(1, "Found inner } in enum");
+ --depth;
+ }
+ else
+ {
+ Debug.log(1, "Found enum }");
+ parser.classClosed();
+ return a + 1;
+ }
+ }
+ }
+ }
+ int rc=parser.parse(source, endIndex, parser.getClassLevelComponents());
+ return rc;
+ }
+
+ }
+
+
+public class Parser {
+
+
+ static int skipExpression(char[] source, int endIndex, int level, char delimiter) throws ParseException {
+
+ int orgEndIndex=endIndex;
+
+ final int STATE_NORMAL=1;
+ final int STATE_STARC=2;
+ final int STATE_SLASHC=3;
+ final int STATE_CHAR=4;
+ final int STATE_STRING=5;
+
+ int state=STATE_NORMAL;
+ int prev=0;
+ for (; !((level==0 && state==STATE_NORMAL && (delimiter=='\0' || source[endIndex]==delimiter))) && endIndex<source.length; ++endIndex) {
+ int c=source[endIndex];
+ if (state==STATE_NORMAL) {
+ if (c=='}') --level;
+ else if (c=='{') ++level;
+ else if (c=='/' && prev=='/') { state=STATE_SLASHC; c=0; }
+ else if (c=='*' && prev=='/') { state=STATE_STARC; c=0; }
+ else if (c=='\'' && prev!='\\') { state=STATE_CHAR; c=0; }
+ else if (c=='\"' && prev!='\\') { state=STATE_STRING; c=0; }
+ }
+ else if (state==STATE_SLASHC) {
+ if (c=='\n') state=STATE_NORMAL;
+ }
+ else if (state==STATE_CHAR) {
+ if (c=='\'' && prev!='\\') state=STATE_NORMAL;
+ else if (c=='\\' && prev=='\\') c=0;
+ }
+ else if (state==STATE_STRING) {
+ if (c=='\"' && prev!='\\') state=STATE_NORMAL;
+ else if (c=='\\' && prev=='\\') c=0;
+ }
+ else {
+ if (c=='/' && prev=='*') { state=STATE_NORMAL; c=0; }
+ }
+ prev=c;
+ }
+ if (level>0)
+ throw new ParseException("Unexpected end of source.");
+ else {
+ String rc=new String(source, orgEndIndex, endIndex-orgEndIndex);
+ return endIndex;
+ }
+ }
+
+ private boolean addComments = false;
+
+ public boolean getAddComments()
+ {
+ return this.addComments;
+ }
+
+ public static final String WHITESPACE=" \t\r\n ";
+
+ public static final boolean isWhitespace(char c) {
+ return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == ' ');
+ //return WHITESPACE.indexOf(c)>=0;
+ }
+
+ private int currentLine;
+
+ static char[] loadFile(final File file, String encoding)
+ throws IOException
+ {
+ InputStream in = new FileInputStream(file);
+ NotifyingInputStreamReader notifyingInput
+ = new NotifyingInputStreamReader(in, encoding);
+ notifyingInput.addMalformedInputListener(new MalformedInputListener() {
+ public void malformedInputEncountered(MalformedInputEvent event) {
+ Main.getRootDoc().printWarning("Illegal character in file " + file + ", line " + event.getLineNumber() + ", column " + event.getColumnNumber());
+ try {
+ Main.getRootDoc().printWarning(IOToolkit.getLineFromFile(file, event.getLineNumber()));
+ Main.getRootDoc().printWarning(IOToolkit.getColumnDisplayLine(event.getColumnNumber()));
+ }
+ catch (IOException ignore) {
+ }
+ }
+ });
+ Reader reader
+ = new BufferedReader(notifyingInput);
+ char[] result = IOToolkit.readFully(reader);
+ reader.close();
+ return result;
+ }
+
+ private SourceComponent[] sourceLevelComponents;
+ private SourceComponent[] classLevelComponents;
+
+ public SourceComponent[] getClassLevelComponents()
+ {
+ return this.classLevelComponents;
+ }
+
+ public Parser() {
+ try {
+
+ sourceLevelComponents=new SourceComponent[] {
+ new Whitespace(),
+ new CommentComponent(),
+ new SlashSlashCommentComponent(),
+ new PackageComponent(),
+ new EmptyStatementComponent(),
+ new ImportComponent(),
+ new ClassComponent(),
+ };
+
+ classLevelComponents=new SourceComponent[] {
+ new Whitespace(),
+ new BracketClose(),
+ new CommentComponent(),
+ new SlashSlashCommentComponent(),
+ new FunctionComponent(),
+ new StaticBlockComponent(),
+ new ImportComponent(),
+ new ClassComponent(),
+ new FieldComponent(),
+ };
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public int getNumberOfProcessedFiles() {
+ return processedFiles.size();
+ }
+
+ static Set processedFiles = new HashSet();
+
+ ClassDocImpl processSourceFile(File file, boolean addComments,
+ String encoding, String expectedPackageName)
+ throws IOException, ParseException
+ {
+ //System.err.println("Processing " + file + "...");
+ this.currentFile = file;
+ this.currentPackage = null;
+ this.currentPackageName = null;
+ this.expectedPackageName = expectedPackageName;
+ this.outerClass = null;
+ this.boilerplateComment = null;
+
+ this.addComments=addComments;
+
+ if (processedFiles.contains(file)) {
+ return null;
+ }
+
+ processedFiles.add(file);
+
+ Debug.log(1,"Processing file "+file);
+
+ contextStack.clear();
+ ctx=null;
+
+ importedClassesList.clear();
+ importedStringList.clear();
+ importedPackagesList.clear();
+ importedStatementList.clear();
+
+ currentLine = 1;
+
+ char[] source = loadFile(file, encoding);
+
+ try {
+ parse(source, 0, sourceLevelComponents);
+
+ ClassDoc[] importedClasses=(ClassDoc[])importedClassesList.toArray(new ClassDoc[0]);
+ PackageDoc[] importedPackages=(PackageDoc[])importedPackagesList.toArray(new PackageDoc[0]);
+
+ if (Main.DESCEND_IMPORTED) {
+ for (int i=0; i<importedClasses.length; ++i) {
+ Main.getRootDoc().scheduleClass(currentClass, importedClasses[i].qualifiedName());
+ }
+ }
+
+
+ if (contextStack.size()>0) {
+ Debug.log(1,"-->contextStack not empty! size is "+contextStack.size());
+ }
+
+ return outerClass;
+ }
+ catch (IgnoredFileParseException ignore) {
+ Debug.log(1, "File ignored: " + ignore);
+ return null;
+ }
+ }
+
+ int parse(char[] source, int index, SourceComponent[] componentTypes) throws ParseException, IOException {
+
+ while (index<source.length) {
+
+ int match=-1;
+ int i=0;
+ for (; i<componentTypes.length; ++i) {
+ if ((match=componentTypes[i].match(source, index))>=0) {
+ //Debug.log(1,componentTypes[i].getClass().getName()+" ("+match+"/"+source.length+")");
+ break;
+ }
+ }
+
+ if (i<componentTypes.length) {
+ int endIndex=componentTypes[i].getEndIndex(source, match);
+ Debug.log(9, "Processing " + new String(source,index,endIndex-index) + " with " + componentTypes[i]);
+ index=componentTypes[i].process(this, source, index, endIndex);
+ if (index<0) {
+ //Debug.log(9,"exiting parse because of "+componentTypes[i].getClass().getName()+" (\""+new String(source, index, endIndex-index)+"\")");
+ return endIndex;
+ }
+ }
+ else {
+ //Debug.log(9,"index="+index+", source.length()="+source.length);
+ throw new ParseException("unmatched input in line "+currentLine+": "+new String(source, index, Math.min(50,source.length-index)));
+ }
+
+ }
+ //Debug.log(9,"exiting parse normally, index="+index+" source.length="+source.length);
+ return index;
+ }
+
+ private static int countNewLines(String source) {
+ int i=0;
+ int rc=0;
+ while ((i=source.indexOf('\n',i)+1)>0)
+ ++rc;
+ return rc;
+ }
+
+ public void processSourceDir(File dir, String encoding, String expectedPackageName)
+ throws IOException, ParseException
+ {
+ Debug.log(9,"Processing "+dir.getParentFile().getName()+"."+dir.getName());
+ File[] files=dir.listFiles();
+ if (null!=files) {
+ for (int i=0; i<files.length; ++i) {
+ if (files[i].getName().toLowerCase().endsWith(".java")) {
+ processSourceFile(files[i], true, encoding, expectedPackageName);
+ }
+ }
+ }
+ }
+
+ void classOpened(char[] source, int startIndex, int endIndex) throws ParseException, IOException {
+
+ referencedClassesList.clear();
+
+ if (null == currentPackage) {
+
+ if (expectedPackageName != null) {
+ if (null == currentPackageName ||
+ !currentPackageName.equals(expectedPackageName)) {
+
+ Main.getRootDoc().printWarning("Ignoring file " + currentFile + ": (wrong package, " + currentPackageName + "!=" + expectedPackageName + ")");
+ throw new IgnoredFileParseException();
+ }
+ }
+
+ if (null != currentPackageName) {
+ currentPackage = Main.getRootDoc().findOrCreatePackageDoc(currentPackageName);
+ }
+ else {
+ currentPackage = Main.getRootDoc().findOrCreatePackageDoc("");
+ }
+ }
+
+ if (currentPackageName != null)
+ importedStatementList.add(currentPackageName + ".*");
+ importedStatementList.add("java.lang.*");
+
+ ClassDocImpl classDoc
+ = ClassDocImpl.createInstance((ctx!=null)?(ctx.classDoc):null, currentPackage,
+ null,
+ (PackageDoc[])importedPackagesList.toArray(new PackageDoc[0]),
+ source, startIndex, endIndex,
+ importedStatementList);
+
+ if (ctx != null) {
+ ctx.innerClassesList.add(classDoc);
+ if (classDoc.isIncluded()) {
+ ctx.filteredInnerClassesList.add(classDoc);
+ }
+ }
+
+ if (importedClassesList.isEmpty()) {
+ for (Iterator it=importedStringList.iterator(); it.hasNext(); ) {
+ importedClassesList.add(new ClassDocProxy((String)it.next(), classDoc));
+ }
+ }
+ classDoc.setImportedClasses((ClassDoc[])importedClassesList.toArray(new ClassDoc[0]));
+
+ currentPackage.addClass(classDoc);
+
+ currentClass = classDoc;
+
+ if (null == outerClass) {
+ outerClass = classDoc;
+ }
+
+ if (classDoc.superclass()!=null)
+ referencedClassesList.add(classDoc.superclass());
+
+ Debug.log(1,"classOpened "+classDoc+", adding superclass "+classDoc.superclass());
+ Debug.log(1,"Pushing " + ctx);
+ contextStack.push(ctx);
+ ctx=new Context(classDoc);
+ //Debug.log(9,"ctx="+ctx);
+ }
+
+ private Doc[] toArray(List list, Doc[] template)
+ {
+ Doc[] result = (Doc[])list.toArray(template);
+ return result;
+ }
+
+ void classClosed() throws ParseException, IOException {
+ ctx.classDoc.setFields((FieldDoc[])toArray(ctx.fieldList,
+ new FieldDoc[0]));
+ ctx.classDoc.setFilteredFields((FieldDoc[])toArray(ctx.filteredFieldList,
+ new FieldDoc[0]));
+ ctx.classDoc.setSerializableFields((FieldDoc[])toArray(ctx.sfieldList, new FieldDoc[0]));
+ ctx.classDoc.setMethods((MethodDoc[])toArray(ctx.methodList, new MethodDoc[0]));
+ ctx.classDoc.setFilteredMethods((MethodDoc[])toArray(ctx.filteredMethodList, new MethodDoc[0]));
+ ctx.classDoc.setMaybeSerMethodList(ctx.maybeSerMethodList);
+ ctx.classDoc.setConstructors((ConstructorDoc[])toArray(ctx.constructorList, new ConstructorDoc[0]));
+ ctx.classDoc.setFilteredConstructors((ConstructorDoc[])toArray(ctx.filteredConstructorList, new ConstructorDoc[0]));
+
+ ctx.classDoc.setInnerClasses((ClassDocImpl[])toArray(ctx.innerClassesList, new ClassDocImpl[0]));
+ ctx.classDoc.setFilteredInnerClasses((ClassDocImpl[])toArray(ctx.filteredInnerClassesList, new ClassDocImpl[0]));
+ ctx.classDoc.setBoilerplateComment(boilerplateComment);
+
+ Main.getRootDoc().addClassDoc(ctx.classDoc);
+
+ if (Main.DESCEND_INTERFACES) {
+ for (int i=0; i<ctx.classDoc.interfaces().length; ++i) {
+ Main.getRootDoc().scheduleClass(ctx.classDoc, ctx.classDoc.interfaces()[i].qualifiedName());
+ }
+ }
+
+ Debug.log(1,"classClosed: "+ctx.classDoc);
+
+ ctx=(Context)contextStack.pop();
+ Debug.log(1, "Popping " + ctx);
+ ClassDoc[] referencedClasses=(ClassDoc[])referencedClassesList.toArray(new ClassDoc[0]);
+
+ if (Main.DESCEND_SUPERCLASS) {
+ for (int i=0; i<referencedClasses.length; ++i) {
+ Main.getRootDoc().scheduleClass(currentClass, referencedClasses[i].qualifiedName());
+ }
+ }
+ }
+
+ Context ctx = null;
+ Stack contextStack = new Stack();
+ class Context {
+ Context(ClassDocImpl classDoc) { this.classDoc=classDoc; }
+ ClassDocImpl classDoc = null;
+ List fieldList = new LinkedList();
+ List filteredFieldList = new LinkedList();
+ List sfieldList = new LinkedList();
+ List methodList = new LinkedList();
+ List filteredMethodList = new LinkedList();
+ List maybeSerMethodList = new LinkedList();
+ List constructorList = new LinkedList();
+ List filteredConstructorList = new LinkedList();
+ List innerClassesList = new LinkedList();
+ List filteredInnerClassesList = new LinkedList();
+ }
+
+ File currentFile = null;
+ String lastComment = null;
+ String expectedPackageName = null;
+ String currentPackageName = null;
+ PackageDocImpl currentPackage = null;
+ ClassDocImpl currentClass = null;
+ ClassDocImpl outerClass = null;
+ List ordinaryClassesList = new LinkedList();
+ List allClassesList = new LinkedList();
+ List interfacesList = new LinkedList();
+
+ List importedClassesList = new LinkedList();
+ List importedStringList = new LinkedList();
+ List importedPackagesList = new LinkedList();
+ List importedStatementList = new LinkedList();
+
+ List referencedClassesList = new LinkedList();
+
+ String boilerplateComment = null;
+
+ void packageOpened(String packageName) {
+ currentPackageName = packageName;
+ }
+
+ void importEncountered(String importString) throws ParseException, IOException {
+ //Debug.log(9,"importing '"+importString+"'");
+
+ importedStatementList.add(importString);
+
+ if (importString.endsWith(".*")) {
+ importedPackagesList.add(Main.getRootDoc().findOrCreatePackageDoc(importString.substring(0,importString.length()-2)));
+ }
+ else {
+ importedStringList.add(importString);
+ }
+ }
+
+
+ void setLastComment(String lastComment) {
+ this.lastComment=lastComment;
+ }
+
+ String getLastComment() {
+ return this.lastComment;
+ }
+
+ void setBoilerplateComment(String boilerplateComment)
+ {
+ this.boilerplateComment = boilerplateComment;
+ }
+
+ String getBoilerplateComment()
+ {
+ return boilerplateComment;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ProgramElementDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ProgramElementDocImpl.java
new file mode 100644
index 000000000..bdcf61bf6
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ProgramElementDocImpl.java
@@ -0,0 +1,177 @@
+/* gnu.classpath.tools.gjdoc.ProgramElementDocImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.lang.reflect.Modifier;
+
+public abstract class ProgramElementDocImpl extends DocImpl implements ProgramElementDoc {
+
+ protected ClassDoc containingClass;
+ protected PackageDoc containingPackage;
+
+ protected boolean isFinal;
+ protected boolean isStatic;
+ protected int accessLevel=ProgramElementDocImpl.ACCESS_PACKAGEPRIVATE;
+
+ public static final int ACCESS_PUBLIC = 0;
+ public static final int ACCESS_PROTECTED = 1;
+ public static final int ACCESS_PACKAGEPRIVATE = 2;
+ public static final int ACCESS_PRIVATE = 3;
+
+ private static final String[] accessModifiers = { "public ", "protected ", "", "private "};
+
+ public ProgramElementDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ SourcePosition position) {
+ super(position);
+ this.containingClass=containingClass;
+ this.containingPackage=containingPackage;
+ }
+ public ProgramElementDocImpl(ClassDoc containingClass, SourcePosition position) {
+ super(position);
+ this.containingClass=containingClass;
+ this.containingPackage=containingClass.containingPackage();
+ }
+ public ProgramElementDocImpl(ClassDoc containingClass,
+ PackageDoc containingPackage,
+ int accessLevel,
+ boolean isFinal,
+ boolean isStatic,
+ SourcePosition position) {
+ super(position);
+ this.containingClass=containingClass;
+ this.containingPackage=containingPackage;
+ this.accessLevel=accessLevel;
+ this.isFinal=isFinal;
+ this.isStatic=isStatic;
+ }
+
+ //Get the containing class of this program element.
+ public ClassDoc containingClass() {
+ return containingClass;
+ }
+
+ // Get the package that this program element is contained in.
+ public PackageDoc containingPackage() {
+ return containingPackage;
+ }
+
+ // Return true if this program element is final
+ public boolean isFinal() {
+ return isFinal;
+ }
+
+ // Return true if this program element is package private
+ public boolean isPackagePrivate() {
+ return accessLevel==ACCESS_PACKAGEPRIVATE;
+ }
+
+ // Return true if this program element is private
+ public boolean isPrivate() {
+ return accessLevel==ACCESS_PRIVATE;
+ }
+
+ // Return true if this program element is protected
+ public boolean isProtected() {
+ return accessLevel==ACCESS_PROTECTED;
+ }
+
+ // Return true if this program element is public
+ public boolean isPublic() {
+ return accessLevel==ACCESS_PUBLIC;
+ }
+
+ // Return true if this program element is static
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ // Get modifiers string.
+ public String modifiers() {
+ return
+ (accessModifiers[accessLevel]+
+ (isStatic()?"static ":"")+
+ (isFinal()?"final ":"")).trim();
+ }
+
+ // Get the modifier specifier integer.
+ public int modifierSpecifier() {
+ return (isStatic()?Modifier.STATIC:0)
+ | (isFinal()?Modifier.FINAL:0)
+ | (isPublic()?Modifier.PUBLIC:0)
+ | (isProtected()?Modifier.PROTECTED:0)
+ | (isPrivate()?Modifier.PRIVATE:0)
+// | (isAbstract()?Modifier.ABSTRACT:0)
+ ;
+ }
+
+ // Get the fully qualified name.
+ public abstract String qualifiedName();
+
+ protected boolean processModifier(String word) {
+ if (word.equals("public")) {
+ accessLevel=ACCESS_PUBLIC;
+ return true;
+ }
+ else if (word.equals("protected")) {
+ accessLevel=ACCESS_PROTECTED;
+ return true;
+ }
+ else if (word.equals("private")) {
+ accessLevel=ACCESS_PRIVATE;
+ return true;
+ }
+ else if (word.equals("static")) {
+ isStatic=true;
+ return true;
+ }
+ else if (word.equals("final")) {
+ isFinal=true;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ void setIsStatic(boolean b) {
+ this.isStatic=b;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/RootDocImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/RootDocImpl.java
new file mode 100644
index 000000000..09d1be73b
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/RootDocImpl.java
@@ -0,0 +1,1334 @@
+/* gnu.classpath.tools.gjdoc.RootDocImpl
+ Copyright (C) 2001, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.io.*;
+import java.lang.reflect.*;
+
+public class RootDocImpl
+ extends DocImpl
+ implements GjdocRootDoc {
+
+ private ErrorReporter reporter = new ErrorReporter();
+
+ private RandomAccessFile rawCommentCache;
+
+ /**
+ * All options and their corresponding values which are not recognized
+ * by Gjdoc. These are passed to the Doclet as "custom options".
+ * Each element in this array is again a String array, with the
+ * option name as first element (including prefix dash) and possible
+ * option values as following elements.
+ */
+ private String[][] customOptionArr;
+
+ /**
+ * All source files explicitly specified on the command line.
+ *
+ * @contains File
+ */
+ private List specifiedSourceFiles = new LinkedList();
+
+ /**
+ * The names of all packages explicitly specified on the
+ * command line.
+ *
+ * @contains String
+ */
+ private Set specifiedPackageNames = new LinkedHashSet();
+
+ /**
+ * Stores all classes specified by the user: those given by
+ * individual class names on the command line, and those
+ * contained in the packages given on the command line.
+ *
+ * @contains ClassDocImpl
+ */
+ private List classesList = new LinkedList(); //new LinkedList();
+
+ /**
+ * Stores all classes loaded in the course of preparing
+ * the documentation data. Maps the fully qualified name
+ * of a class to its ClassDocImpl representation.
+ *
+ * @contains String->ClassDocImpl
+ */
+ private Map classDocMap = new HashMap();
+
+ /**
+ * Stores all packages loaded in the course of preparing
+ * the documentation data. Maps the package name
+ * to its PackageDocImpl representation.
+ *
+ * @contains String->PackageDocImpl
+ */
+ private Map packageDocMap = new HashMap();
+
+ /**
+ * All classes specified by the user, both those explicitly
+ * individually specified on the command line and those contained
+ * in packages specified on the command line (as Array for quick
+ * retrieval by Doclet). This is created from classesList after
+ * all classes have been loaded.
+ */
+ private ClassDocImpl[] classes;
+
+ /**
+ * All classes which were individually specified on the command
+ * line (as Array for quick retrieval by Doclet). This is created
+ * from specifiedClassNames after all classes have been loaded.
+ */
+ private List specifiedClasses;
+
+ /**
+ * All packages which were specified on the command line (as Array
+ * for quick retrieval by Doclet). This is created from
+ * specifiedPackageNames after all classes have been loaded.
+ */
+ private Set specifiedPackages;
+
+
+ /**
+ * Temporarily stores a list of classes which are referenced
+ * by classes already loaded and which still have to be
+ * resolved.
+ */
+ private List scheduledClasses=new LinkedList();
+
+ private List sourcePath;
+
+ private String sourceEncoding;
+
+ private Parser parser = new Parser();
+
+ private Set unlocatableReportedSet = new HashSet();
+
+ private Set inaccessibleReportedSet = new HashSet();
+
+ //--------------------------------------------------------------------------
+ //
+ // Implementation of RootDoc interface
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Return classes and interfaces to be documented.
+ */
+ public ClassDoc[] classes() { return classes; }
+
+ /**
+ * Return a ClassDoc object for the specified class/interface
+ * name.
+ *
+ * @return a ClassDoc object describing the given class, or
+ * <code>null</code> if no corresponding ClassDoc object
+ * has been constructed.
+ */
+ public ClassDoc classNamed(String qualifiedName) {
+ return (ClassDoc)classDocMap.get(qualifiedName);
+ }
+
+ /**
+ * Return an xxx
+ */
+ public String[][] options() { return customOptionArr; }
+
+ // Return a PackageDoc for the specified package name
+ public PackageDoc packageNamed(String name) {
+ return (PackageDoc)packageDocMap.get(name);
+ }
+
+
+ // classes and interfaces specified on the command line.
+ public ClassDoc[] specifiedClasses()
+ {
+ return (ClassDocImpl[]) specifiedClasses.toArray(new ClassDocImpl[0]);
+ }
+
+ // packages specified on the command line.
+ public PackageDoc[] specifiedPackages()
+ {
+ return (PackageDocImpl[])specifiedPackages.toArray(new PackageDocImpl[0]);
+ }
+
+ // Print error message, increment error count.
+ public void printError(java.lang.String msg) {
+ reporter.printError(msg);
+ }
+
+ // Print error message, increment error count.
+ public void printFatal(java.lang.String msg) {
+ reporter.printFatal(msg);
+ }
+
+ // Print a message.
+ public void printNotice(java.lang.String msg) {
+ reporter.printNotice(msg);
+ }
+
+ // Print warning message, increment warning count.
+ public void printWarning(java.lang.String msg) {
+ reporter.printWarning(msg);
+ }
+
+ public String name() {
+ return "RootDoc";
+ }
+
+ public ErrorReporter getReporter() {
+ return reporter;
+ }
+
+ public void build() throws ParseException, IOException {
+
+ //--- Create a temporary random access file for caching comment text.
+
+ //File rawCommentCacheFile=File.createTempFile("gjdoc_rawcomment",".cache");
+ File rawCommentCacheFile = new File("gjdoc_rawcomment.cache");
+ rawCommentCacheFile.deleteOnExit();
+ rawCommentCache = new RandomAccessFile(rawCommentCacheFile, "rw");
+
+ //--- Parse all files in "java.lang".
+
+ List javaLangSourceDirs = findSourceFiles("java/lang");
+ if (!javaLangSourceDirs.isEmpty()) {
+ Iterator it = javaLangSourceDirs.iterator();
+ while (it.hasNext()) {
+ File javaLangSourceDir = (File)it.next();
+ parser.processSourceDir(javaLangSourceDir,
+ sourceEncoding, "java.lang");
+ }
+ }
+ else {
+
+ Debug.log(1, "Sourcepath is "+sourcePath);
+
+ // Core docs not included in source-path:
+ // we need to gather the information about java.lang
+ // classes via reflection...
+
+ }
+
+ //--- Parse all files in explicitly specified package directories.
+
+ for (Iterator it=specifiedPackageNames.iterator(); it.hasNext(); ) {
+
+ String specifiedPackageName = (String)it.next();
+ String displayPackageName = specifiedPackageName;
+ if (null == displayPackageName || 0 == displayPackageName.length()) {
+ displayPackageName = "<unnamed>";
+ }
+ printNotice("Loading classes for package "+displayPackageName+"...");
+ String relPath;
+ if (null != specifiedPackageName) {
+ relPath = specifiedPackageName.replace('.',File.separatorChar);
+ }
+ else {
+ relPath = "";
+ }
+ List sourceDirs = findSourceFiles(relPath);
+ if (!sourceDirs.isEmpty()) {
+ Iterator sourceDirIt = sourceDirs.iterator();
+ while (sourceDirIt.hasNext()) {
+ File sourceDir = (File)sourceDirIt.next();
+ parser.processSourceDir(sourceDir, sourceEncoding, specifiedPackageName);
+ }
+ }
+ else {
+ printError("Package '"+specifiedPackageName+"' not found.");
+ }
+ }
+
+ specifiedClasses = new LinkedList();
+
+ //--- Parse all explicitly specified source files.
+
+ for (Iterator it=specifiedSourceFiles.iterator(); it.hasNext(); ) {
+
+ File specifiedSourceFile = (File)it.next();
+ printNotice("Loading source file "+specifiedSourceFile+" ...");
+ ClassDocImpl classDoc = parser.processSourceFile(specifiedSourceFile, true, sourceEncoding, null);
+ if (null != classDoc) {
+ specifiedClasses.add(classDoc);
+ classesList.add(classDoc);
+ classDoc.setIsIncluded(true);
+ addPackageDoc(classDoc.containingPackage());
+ }
+ }
+
+
+ //--- Let the user know that all specified classes are loaded.
+
+ printNotice("Constructing Javadoc information...");
+
+ //--- Load all classes implicitly referenced by explicitly specified classes.
+
+ loadScheduledClasses(parser);
+
+ printNotice("Resolving references in comments...");
+
+ resolveComments();
+
+ //--- Resolve pending references in all ClassDocImpls
+
+ printNotice("Resolving references in classes...");
+
+ for (Iterator it = classDocMap.values().iterator(); it.hasNext(); ) {
+ ClassDoc cd=(ClassDoc)it.next();
+ if (cd instanceof ClassDocImpl) {
+ ((ClassDocImpl)cd).resolve();
+ }
+ }
+
+ //--- Resolve pending references in all PackageDocImpls
+
+ printNotice("Resolving references in packages...");
+
+ for (Iterator it = packageDocMap.values().iterator(); it.hasNext(); ) {
+ PackageDocImpl pd=(PackageDocImpl)it.next();
+ pd.resolve();
+ }
+
+ //--- Assemble the array with all specified packages
+
+ specifiedPackages = new LinkedHashSet();
+ for (Iterator it = specifiedPackageNames.iterator(); it.hasNext(); ) {
+ String specifiedPackageName = (String)it.next();
+ PackageDoc specifiedPackageDoc = (PackageDoc)packageDocMap.get(specifiedPackageName);
+ if (null!=specifiedPackageDoc) {
+ ((PackageDocImpl)specifiedPackageDoc).setIsIncluded(true);
+ specifiedPackages.add(specifiedPackageDoc);
+
+ ClassDoc[] packageClassDocs=specifiedPackageDoc.allClasses();
+ for (int i=0; i<packageClassDocs.length; ++i) {
+ ClassDocImpl specifiedPackageClassDoc=(ClassDocImpl)packageClassDocs[i];
+
+ specifiedPackageClassDoc.setIsIncluded(true);
+ classesList.add(specifiedPackageClassDoc);
+ }
+ }
+ }
+
+ //--- Resolve pending references in comment data of all classes
+
+ printNotice("Resolving references in class comments...");
+
+ for (Iterator it=classDocMap.values().iterator(); it.hasNext(); ) {
+ ClassDoc cd=(ClassDoc)it.next();
+ if (cd instanceof ClassDocImpl) {
+ ((ClassDocImpl)cd).resolveComments();
+ }
+ }
+
+ //--- Resolve pending references in comment data of all packages
+
+ printNotice("Resolving references in package comments...");
+
+ for (Iterator it=packageDocMap.values().iterator(); it.hasNext(); ) {
+ PackageDocImpl pd=(PackageDocImpl)it.next();
+ pd.resolveComments();
+ }
+
+ //--- Create array with all loaded classes
+
+ this.classes=(ClassDocImpl[])classesList.toArray(new ClassDocImpl[0]);
+ Arrays.sort(this.classes);
+
+ //--- Close comment cache
+
+ parser = null;
+ System.gc();
+ System.gc();
+ }
+
+ public long writeRawComment(String rawComment) {
+ try {
+ long pos=rawCommentCache.getFilePointer();
+ //rawCommentCache.writeUTF(rawComment);
+ byte[] bytes = rawComment.getBytes("utf-8");
+ rawCommentCache.writeInt(bytes.length);
+ rawCommentCache.write(bytes);
+ return pos;
+ }
+ catch (IOException e) {
+ printFatal("Cannot write to comment cache: "+e.getMessage());
+ return -1;
+ }
+ }
+
+ public String readRawComment(long pos) {
+ try {
+ rawCommentCache.seek(pos);
+ int sz = rawCommentCache.readInt();
+ byte[] bytes = new byte[sz];
+ rawCommentCache.read(bytes);
+ return new String(bytes, "utf-8");
+ //return rawCommentCache.readUTF();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ printFatal("Cannot read from comment cache: "+e.getMessage());
+ return null;
+ }
+ }
+
+ List findSourceFiles(String relPath) {
+
+ List result = new LinkedList();
+ for (Iterator it = sourcePath.iterator(); it.hasNext(); ) {
+ File path = (File)it.next();
+ File file = new File(path, relPath);
+ if (file.exists()) {
+ result.add(file);
+ }
+ }
+
+ return result;
+ }
+
+ PackageDocImpl findOrCreatePackageDoc(String packageName) {
+ PackageDocImpl rc=(PackageDocImpl)getPackageDoc(packageName);
+ if (null==rc) {
+ rc=new PackageDocImpl(packageName);
+ if (specifiedPackageNames.contains(packageName)) {
+ String packageDirectoryName = packageName.replace('.', File.separatorChar);
+ List packageDirectories = findSourceFiles(packageDirectoryName);
+ Iterator it = packageDirectories.iterator();
+ boolean packageDocFound = false;
+ while (it.hasNext()) {
+ File packageDirectory = (File)it.next();
+ File packageDocFile = new File(packageDirectory, "package.html");
+ rc.setPackageDirectory(packageDirectory);
+ packageDocFound = true;
+ if (null!=packageDocFile && packageDocFile.exists()) {
+ try {
+ rc.setRawCommentText(readHtmlBody(packageDocFile));
+ }
+ catch (IOException e) {
+ printWarning("Error while reading documentation for package "+packageName+": "+e.getMessage());
+ }
+ break;
+ }
+ }
+ if (!packageDocFound) {
+ printNotice("No description found for package "+packageName);
+ }
+ }
+ addPackageDoc(rc);
+ }
+ return rc;
+ }
+
+ public void addClassDoc(ClassDoc cd) {
+ classDocMap.put(cd.qualifiedName(), cd);
+ }
+
+ public void addClassDocRecursive(ClassDoc cd) {
+ classDocMap.put(cd.qualifiedName(), cd);
+ ClassDoc[] innerClasses = cd.innerClasses(false);
+ for (int i=0; i<innerClasses.length; ++i) {
+ addClassDocRecursive(innerClasses[i]);
+ }
+ }
+
+ public void addPackageDoc(PackageDoc pd) {
+ packageDocMap.put(pd.name(), pd);
+ }
+
+ public PackageDocImpl getPackageDoc(String name) {
+ return (PackageDocImpl)packageDocMap.get(name);
+ }
+
+ public ClassDocImpl getClassDoc(String qualifiedName) {
+ return (ClassDocImpl)classDocMap.get(qualifiedName);
+ }
+
+ class ScheduledClass {
+
+ ClassDoc contextClass;
+ String qualifiedName;
+ ScheduledClass(ClassDoc contextClass, String qualifiedName) {
+ this.contextClass=contextClass;
+ this.qualifiedName=qualifiedName;
+ }
+
+ public String toString() { return "ScheduledClass{"+qualifiedName+"}"; }
+ }
+
+ public void scheduleClass(ClassDoc context, String qualifiedName) throws ParseException, IOException {
+
+ if (classDocMap.get(qualifiedName)==null) {
+
+ //Debug.log(9,"Scheduling "+qualifiedName+", context "+context+".");
+ //System.err.println("Scheduling " + qualifiedName + ", context " + context);
+
+ scheduledClasses.add(new ScheduledClass(context, qualifiedName));
+ }
+ }
+
+ /**
+ * Load all classes that were implictly referenced by the classes
+ * (already loaded) that the user explicitly specified on the
+ * command line.
+ *
+ * For example, if the user generates Documentation for his simple
+ * 'class Test {}', which of course 'extends java.lang.Object',
+ * then 'java.lang.Object' is implicitly referenced because it is
+ * the base class of Test.
+ *
+ * Gjdoc needs a ClassDocImpl representation of all classes
+ * implicitly referenced through derivation (base class),
+ * or implementation (interface), or field type, method argument
+ * type, or method return type.
+ *
+ * The task of this method is to ensure that Gjdoc has all this
+ * information at hand when it exits.
+ *
+ *
+ */
+ public void loadScheduledClasses(Parser parser) throws ParseException, IOException {
+
+ // Because the referenced classes could in turn reference other
+ // classes, this method runs as long as there are still unloaded
+ // classes.
+
+ while (!scheduledClasses.isEmpty()) {
+
+ // Make a copy of scheduledClasses and empty it. This
+ // prevents any Concurrent Modification issues.
+ // As the copy won't need to grow (as it won't change)
+ // we make it an Array for performance reasons.
+
+ ScheduledClass[] scheduledClassesArr = (ScheduledClass[])scheduledClasses.toArray(new ScheduledClass[0]);
+ scheduledClasses.clear();
+
+ // Load each class specified in our array copy
+
+ for (int i=0; i<scheduledClassesArr.length; ++i) {
+
+ // The name of the class we are looking for. This name
+ // needs not be fully qualified.
+
+ String scheduledClassName=scheduledClassesArr[i].qualifiedName;
+
+ // The ClassDoc in whose context the scheduled class was looked for.
+ // This is necessary in order to resolve non-fully qualified
+ // class names.
+ ClassDoc scheduledClassContext=scheduledClassesArr[i].contextClass;
+
+ // If there already is a class doc with this name, skip. There's
+ // nothing to do for us.
+ if (classDocMap.get(scheduledClassName)!=null) {
+ continue;
+ }
+
+ try {
+ // Try to load the class
+ //printNotice("Trying to load " + scheduledClassName);
+ loadScheduledClass(parser, scheduledClassName, scheduledClassContext);
+ }
+ catch (ParseException e) {
+
+ /**********************************************************
+
+ // Check whether the following is necessary at all.
+
+
+ if (scheduledClassName.indexOf('.')>0) {
+
+ // Maybe the dotted notation doesn't mean a package
+ // name but instead an inner class, as in 'Outer.Inner'.
+ // so let's assume this and try to load the outer class.
+
+ String outerClass="";
+ for (StringTokenizer st=new StringTokenizer(scheduledClassName,"."); st.hasMoreTokens(); ) {
+ if (outerClass.length()>0) outerClass+=".";
+ outerClass+=st.nextToken();
+ if (!st.hasMoreTokens()) break;
+ try {
+ loadClass(outerClass);
+ //FIXME: shouldn't this be loadScheduledClass(outerClass, scheduledClassContext); ???
+ continue;
+ }
+ catch (Exception ee) {
+ // Ignore: try next level
+ }
+ }
+ }
+
+ **********************************************************/
+
+ // If we arrive here, the class could not be found
+
+ printWarning("Couldn't load class "+scheduledClassName+" referenced by "+scheduledClassContext);
+
+ //FIXME: shouldn't this be throw new Error("cannot load: "+scheduledClassName);
+ }
+ }
+ }
+ }
+
+ private void loadScheduledClass(Parser parser, String scheduledClassName, ClassDoc scheduledClassContext) throws ParseException, IOException {
+
+ ClassDoc loadedClass=(ClassDoc)scheduledClassContext.findClass(scheduledClassName);
+
+ if (loadedClass==null || loadedClass instanceof ClassDocProxy) {
+
+ ClassDoc classDoc = findScheduledClassFile(scheduledClassName, scheduledClassContext);
+ if (null != classDoc) {
+
+ if (classDoc instanceof ClassDocReflectedImpl) {
+ Main.getRootDoc().addClassDocRecursive(classDoc);
+ }
+
+ if (Main.DESCEND_SUPERCLASS
+ && null != classDoc.superclass()
+ && (classDoc.superclass() instanceof ClassDocProxy)) {
+ scheduleClass(classDoc, classDoc.superclass().qualifiedName());
+ }
+ }
+ else {
+ // It might be an inner class of one of the outer/super classes.
+ // But we can only check that when they are all fully loaded.
+ boolean retryLater = false;
+
+ int numberOfProcessedFilesBefore = parser.getNumberOfProcessedFiles();
+
+ ClassDoc cc = scheduledClassContext.containingClass();
+ while (cc != null && !retryLater) {
+ ClassDoc sc = cc.superclass();
+ while (sc != null && !retryLater) {
+ if (sc instanceof ClassDocProxy) {
+ ((ClassDocImpl)cc).resolve();
+ retryLater = true;
+ }
+ sc = sc.superclass();
+ }
+ cc = cc.containingClass();
+ }
+
+ // Now that outer/super references have been resolved, try again
+ // to find the class.
+
+ loadedClass = (ClassDoc)scheduledClassContext.findClass(scheduledClassName);
+
+ int numberOfProcessedFilesAfter = parser.getNumberOfProcessedFiles();
+
+ boolean filesWereProcessed = numberOfProcessedFilesAfter > numberOfProcessedFilesBefore;
+
+ // Only re-schedule class if additional files have been processed
+ // If there haven't, there's no point in re-scheduling.
+ // Will avoid infinite loops of re-scheduling
+ if (null == loadedClass && retryLater && filesWereProcessed)
+ scheduleClass(scheduledClassContext, scheduledClassName);
+
+ /* A warning needn't be emitted - this is normal, can happen
+ if the scheduled class is in a package which is not
+ included on the command line.
+
+ else if (null == loadedClass)
+ printWarning("Can't find scheduled class '"
+ + scheduledClassName
+ + "' in context '"
+ + scheduledClassContext.qualifiedName()
+ + "'");
+ */
+ }
+ }
+ }
+
+ private static interface ResolvedImport
+ {
+ public String match(String name);
+ public boolean mismatch(String name);
+ public ClassDoc tryFetch(String name);
+ }
+
+ private class ResolvedImportNotFound
+ implements ResolvedImport
+ {
+ private String importSpecifier;
+ private String name;
+
+ ResolvedImportNotFound(String importSpecifier)
+ {
+ this.importSpecifier = importSpecifier;
+ int ndx = importSpecifier.lastIndexOf('.');
+ if (ndx >= 0) {
+ this.name = importSpecifier.substring(ndx + 1);
+ }
+ else {
+ this.name = importSpecifier;
+ }
+ }
+
+ public String toString()
+ {
+ return "ResolvedImportNotFound{" + importSpecifier + "}";
+ }
+
+ public String match(String name)
+ {
+ if ((name.equals(this.name)) || (importSpecifier.equals(name)))
+ return this.name;
+ // FIXME: note that we don't handle on-demand imports here.
+ return null;
+ }
+
+ public boolean mismatch(String name)
+ {
+ return true; // FIXME!
+ }
+
+ public ClassDoc tryFetch(String name)
+ {
+ return null;
+ }
+ }
+
+ private class ResolvedImportPackageFile
+ implements ResolvedImport
+ {
+ private Set topLevelClassNames;
+ private File packageFile;
+ private String packageName;
+ private Map cache = new HashMap();
+
+ ResolvedImportPackageFile(File packageFile, String packageName)
+ {
+ this.packageFile = packageFile;
+ this.packageName = packageName;
+ topLevelClassNames = new HashSet();
+ File[] files = packageFile.listFiles();
+ for (int i=0; i<files.length; ++i) {
+ if (!files[i].isDirectory() && files[i].getName().endsWith(".java")) {
+ String topLevelClassName = files[i].getName();
+ topLevelClassName
+ = topLevelClassName.substring(0, topLevelClassName.length() - 5);
+ topLevelClassNames.add(topLevelClassName);
+ }
+ }
+ }
+
+ public String match(String name)
+ {
+ ClassDoc loadedClass = classNamed(packageName + "." + name);
+ if (null != loadedClass) {
+ return loadedClass.qualifiedName();
+ }
+ else {
+ String topLevelName = name;
+ int ndx = topLevelName.indexOf('.');
+ String innerClassName = null;
+ if (ndx > 0) {
+ innerClassName = topLevelName.substring(ndx + 1);
+ topLevelName = topLevelName.substring(0, ndx);
+ }
+
+ if (topLevelClassNames.contains(topLevelName)) {
+ //System.err.println(this + ".match returns " + packageName + "." + name);
+ return packageName + "." + name;
+ }
+ // FIXME: inner classes
+ else {
+ return null;
+ }
+ }
+ }
+
+ public boolean mismatch(String name)
+ {
+ return null == match(name);
+ }
+
+ public ClassDoc tryFetch(String name)
+ {
+ ClassDoc loadedClass = classNamed(packageName + "." + name);
+ if (null != loadedClass) {
+ return loadedClass;
+ }
+ else if (null != match(name)) {
+
+ String topLevelName = name;
+ int ndx = topLevelName.indexOf('.');
+ String innerClassName = null;
+ if (ndx > 0) {
+ innerClassName = topLevelName.substring(ndx + 1);
+ topLevelName = topLevelName.substring(0, ndx);
+ }
+
+ ClassDoc topLevelClass = (ClassDoc)cache.get(topLevelName);
+ if (null == topLevelClass) {
+ File classFile = new File(packageFile, topLevelName + ".java");
+ try {
+ // FIXME: inner classes
+ topLevelClass = parser.processSourceFile(classFile, false, sourceEncoding, null);
+ }
+ catch (Exception ignore) {
+ printWarning("Could not parse source file " + classFile);
+ }
+ cache.put(topLevelName, topLevelClass);
+ }
+ if (null == innerClassName) {
+ return topLevelClass;
+ }
+ else {
+ return getInnerClass(topLevelClass, innerClassName);
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String toString()
+ {
+ return "ResolvedImportPackageFile{" + packageFile + "," + packageName + "}";
+ }
+ }
+
+ private ClassDoc getInnerClass(ClassDoc topLevelClass, String innerClassName)
+ {
+ StringTokenizer st = new StringTokenizer(innerClassName, ".");
+ outer:
+
+ while (st.hasMoreTokens()) {
+ String innerClassNameComponent = st.nextToken();
+ ClassDoc[] innerClasses = topLevelClass.innerClasses();
+ for (int i=0; i<innerClasses.length; ++i) {
+ if (innerClasses[i].name().equals(innerClassNameComponent)) {
+ topLevelClass = innerClasses[i];
+ continue outer;
+ }
+ }
+ printWarning("Could not find inner class " + innerClassName + " in class " + topLevelClass.qualifiedName());
+ return null;
+ }
+ return topLevelClass;
+ }
+
+ private class ResolvedImportClassFile
+ implements ResolvedImport
+ {
+ private File classFile;
+ private String innerClassName;
+ private String name;
+ private ClassDoc classDoc;
+ private boolean alreadyFetched;
+ private String qualifiedName;
+
+ ResolvedImportClassFile(File classFile, String innerClassName, String name, String qualifiedName)
+ {
+ this.classFile = classFile;
+ this.innerClassName = innerClassName;
+ this.name = name;
+ this.qualifiedName = qualifiedName;
+ }
+
+ public String toString()
+ {
+ return "ResolvedImportClassFile{" + classFile + "," + innerClassName + "}";
+ }
+
+ public String match(String name)
+ {
+ String topLevelName = name;
+ int ndx = topLevelName.indexOf('.');
+
+ String _innerClassName = null;
+ if (ndx > 0) {
+ _innerClassName = topLevelName.substring(ndx + 1);
+ topLevelName = topLevelName.substring(0, ndx);
+ }
+
+ if (this.name.equals(topLevelName)) {
+ if (null == _innerClassName) {
+ return qualifiedName;
+ }
+ else {
+ return qualifiedName + "." + _innerClassName;
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ public boolean mismatch(String name)
+ {
+ return null == match(name);
+ }
+
+ public ClassDoc tryFetch(String name)
+ {
+ if (null != match(name)) {
+ ClassDoc topLevelClass = null;
+ if (alreadyFetched) {
+ topLevelClass = classDoc;
+ }
+ else {
+ alreadyFetched = true;
+ try {
+ topLevelClass = parser.processSourceFile(classFile, false, sourceEncoding, null);
+ }
+ catch (Exception ignore) {
+ printWarning("Could not parse source file " + classFile);
+ }
+ }
+ if (null == topLevelClass) {
+ return null;
+ }
+ else {
+ return getInnerClass(topLevelClass, innerClassName);
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String getName()
+ {
+ if (innerClassName != null) {
+ return name + innerClassName;
+ }
+ else {
+ return name;
+ }
+ }
+ }
+
+ private class ResolvedImportReflectionClass
+ implements ResolvedImport
+ {
+ private Class clazz;
+ private String name;
+
+ ResolvedImportReflectionClass(Class clazz)
+ {
+ this.clazz = clazz;
+ String className = clazz.getName();
+ int ndx = className.lastIndexOf('.');
+ if (ndx >= 0) {
+ this.name = className.substring(ndx + 1);
+ }
+ else {
+ this.name = className;
+ }
+ }
+
+ public String toString()
+ {
+ return "ResolvedImportReflectionClass{" + clazz.getName() + "}";
+ }
+
+ public String match(String name)
+ {
+ if ((this.name.equals(name)) || (clazz.getName().equals(name))) {
+ return clazz.getName();
+ }
+ else {
+ return null;
+ }
+ }
+
+ public boolean mismatch(String name)
+ {
+ return null == match(name);
+ }
+
+ public ClassDoc tryFetch(String name)
+ {
+ if (null != match(name)) {
+ return new ClassDocReflectedImpl(clazz);
+ }
+ // FIXME: inner classes?
+ else {
+ return null;
+ }
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+ }
+
+ private class ResolvedImportReflectionPackage
+ implements ResolvedImport
+ {
+ private String packagePrefix;
+
+ ResolvedImportReflectionPackage(String packagePrefix)
+ {
+ this.packagePrefix = packagePrefix;
+ }
+
+ public String toString()
+ {
+ return "ResolvedImportReflectionPackage{" + packagePrefix + ".*}";
+ }
+
+ public String match(String name)
+ {
+ try {
+ Class clazz = Class.forName(packagePrefix + "." + name);
+ return clazz.getName();
+ }
+ catch (Exception e) {
+ return null;
+ }
+ }
+
+ public boolean mismatch(String name)
+ {
+ return null == match(name);
+ }
+
+ public ClassDoc tryFetch(String name)
+ {
+ try {
+ Class clazz = Class.forName(packagePrefix + name);
+ return ClassDocReflectedImpl.newInstance(clazz);
+ }
+ catch (Exception e) {
+ return null;
+ }
+ }
+
+ public String getName()
+ {
+ return packagePrefix;
+ }
+ }
+
+ private List unlocatablePrefixes = new LinkedList();
+
+ private ResolvedImport resolveImport(String importSpecifier)
+ {
+ ResolvedImport result = resolveImportFileSystem(importSpecifier);
+ if (null == result && Main.getInstance().isReflectionEnabled()) {
+ result = resolveImportReflection(importSpecifier);
+ }
+ if (null == result) {
+ result = new ResolvedImportNotFound(importSpecifier);
+ }
+ return result;
+ }
+
+ private ResolvedImport resolveImportReflection(String importSpecifier)
+ {
+ String importedPackageOrClass = importSpecifier;
+ if (importedPackageOrClass.endsWith(".*")) {
+ importedPackageOrClass = importedPackageOrClass.substring(0, importedPackageOrClass.length() - 2);
+
+ return new ResolvedImportReflectionPackage(importedPackageOrClass);
+
+ //return null;
+ }
+ else {
+ try {
+ Class importedClass = Class.forName(importSpecifier);
+ return new ResolvedImportReflectionClass(importedClass);
+ }
+ catch (Throwable ignore) {
+ return null;
+ }
+ }
+ }
+
+ private ResolvedImport resolveImportFileSystem(String importSpecifier)
+ {
+ for (Iterator it = unlocatablePrefixes.iterator(); it.hasNext(); ) {
+ String unlocatablePrefix = (String)it.next();
+ if (importSpecifier.startsWith(unlocatablePrefix)) {
+ return null;
+ }
+ }
+
+ String longestUnlocatablePrefix = "";
+
+ for (Iterator it=sourcePath.iterator(); it.hasNext(); ) {
+
+ File _sourcePath = (File)it.next();
+
+ StringBuffer packageOrClassPrefix = new StringBuffer();
+ StringTokenizer st = new StringTokenizer(importSpecifier, ".");
+ while (st.hasMoreTokens() && _sourcePath.isDirectory()) {
+ String token = st.nextToken();
+ if ("*".equals(token)) {
+ return new ResolvedImportPackageFile(_sourcePath,
+ packageOrClassPrefix.substring(0, packageOrClassPrefix.length() - 1));
+ }
+ else {
+ packageOrClassPrefix.append(token);
+ packageOrClassPrefix.append('.');
+ File classFile = new File(_sourcePath, token + ".java");
+ //System.err.println(" looking for file " + classFile);
+ if (classFile.exists()) {
+ StringBuffer innerClassName = new StringBuffer();
+ while (st.hasMoreTokens()) {
+ token = st.nextToken();
+ if (innerClassName.length() > 0) {
+ innerClassName.append('.');
+ }
+ innerClassName.append(token);
+ }
+ return new ResolvedImportClassFile(classFile, innerClassName.toString(), token, importSpecifier);
+ }
+ else {
+ _sourcePath = new File(_sourcePath, token);
+ }
+ }
+ }
+ if (st.hasMoreTokens()) {
+ if (packageOrClassPrefix.length() > longestUnlocatablePrefix.length()) {
+ longestUnlocatablePrefix = packageOrClassPrefix.toString();
+ }
+ }
+ }
+
+ if (longestUnlocatablePrefix.length() > 0) {
+ unlocatablePrefixes.add(longestUnlocatablePrefix);
+ }
+
+ return null;
+ }
+
+ private Map resolvedImportCache = new HashMap();
+
+ private ResolvedImport getResolvedImport(String importSpecifier)
+ {
+ ResolvedImport result
+ = (ResolvedImport)resolvedImportCache.get(importSpecifier);
+ if (null == result) {
+ result = resolveImport(importSpecifier);
+ resolvedImportCache.put(importSpecifier, result);
+ }
+ return result;
+ }
+
+ public String resolveClassName(String className, ClassDocImpl context)
+ {
+ Iterator it = context.getImportSpecifierList().iterator();
+ while (it.hasNext()) {
+ String importSpecifier = (String)it.next();
+ ResolvedImport resolvedImport = getResolvedImport(importSpecifier);
+ String resolvedScheduledClassName = resolvedImport.match(className);
+
+ if (null != resolvedScheduledClassName) {
+ return resolvedScheduledClassName;
+ }
+ }
+ return className;
+ }
+
+ public ClassDoc findScheduledClassFile(String scheduledClassName,
+ ClassDoc scheduledClassContext)
+ throws ParseException, IOException
+ {
+ String resolvedScheduledClassName = null;
+
+ if (scheduledClassContext instanceof ClassDocImpl) {
+
+ //((ClassDocImpl)scheduledClassContext).resolveReferencedName(scheduledClassName);
+ Iterator it = ((ClassDocImpl)scheduledClassContext).getImportSpecifierList().iterator();
+ while (it.hasNext()) {
+ String importSpecifier = (String)it.next();
+ ResolvedImport resolvedImport = getResolvedImport(importSpecifier);
+ //System.err.println(" looking in import '" + resolvedImport + "'");
+ resolvedScheduledClassName = resolvedImport.match(scheduledClassName);
+ if (null != resolvedScheduledClassName) {
+ ClassDoc result = resolvedImport.tryFetch(scheduledClassName);
+ if (null != result) {
+ return result;
+ }
+ else {
+ if (!inaccessibleReportedSet.contains(scheduledClassName)) {
+ inaccessibleReportedSet.add(scheduledClassName);
+ printWarning("Error while loading class " + scheduledClassName);
+ }
+ // FIXME: output resolved class name here
+ return null;
+ }
+ }
+ }
+ }
+ else {
+ System.err.println("findScheduledClassFile for '" + scheduledClassName + "' in proxy for " + scheduledClassContext);
+ }
+
+ // interpret as fully qualified name on file system
+
+ ResolvedImport fqImport = resolveImportFileSystem(scheduledClassName);
+ if (null != fqImport && fqImport instanceof ResolvedImportClassFile) {
+ return fqImport.tryFetch(((ResolvedImportClassFile)fqImport).getName());
+ }
+
+ // use reflection, assume fully qualified class name
+
+ if (!unlocatableReflectedClassNames.contains(scheduledClassName)) {
+ if (Main.getInstance().isReflectionEnabled()) {
+ try {
+ Class clazz = Class.forName(scheduledClassName);
+ printWarning("Cannot locate class " + scheduledClassName + " on file system, falling back to reflection.");
+ ClassDoc result = new ClassDocReflectedImpl(clazz);
+ return result;
+ }
+ catch (Throwable ignore) {
+ unlocatableReflectedClassNames.add(scheduledClassName);
+ }
+ }
+ else {
+ unlocatableReflectedClassNames.add(scheduledClassName);
+ }
+ }
+
+ if (null == resolvedScheduledClassName) {
+ resolvedScheduledClassName = scheduledClassName;
+ }
+ if (!unlocatableReportedSet.contains(resolvedScheduledClassName)) {
+ unlocatableReportedSet.add(resolvedScheduledClassName);
+ printWarning("Cannot locate class " + resolvedScheduledClassName + " referenced in class " + scheduledClassContext.qualifiedName());
+ }
+ return null;
+ }
+
+ private Set unlocatableReflectedClassNames = new HashSet();
+
+ public static boolean recursiveClasses = false;
+
+ public void addSpecifiedPackageName(String packageName) {
+ specifiedPackageNames.add(packageName);
+ }
+
+ public void addSpecifiedSourceFile(File sourceFile) {
+ specifiedSourceFiles.add(sourceFile);
+ }
+
+ public boolean hasSpecifiedPackagesOrClasses() {
+ return !specifiedPackageNames.isEmpty()
+ || !specifiedSourceFiles.isEmpty();
+ }
+
+ public void setOptions(String[][] customOptionArr) {
+ this.customOptionArr = customOptionArr;
+ }
+
+ public void setSourcePath(List sourcePath) {
+ this.sourcePath = sourcePath;
+ }
+
+ public void finalize() throws Throwable {
+ super.finalize();
+ }
+
+ public void flush()
+ {
+ try {
+ rawCommentCache.close();
+ }
+ catch (IOException e) {
+ printError("Cannot close raw comment cache");
+ }
+
+ rawCommentCache = null;
+ customOptionArr = null;
+ specifiedPackageNames = null;
+ classesList = null;
+ classDocMap = null;
+ packageDocMap = null;
+ classes = null;
+ specifiedClasses = null;
+ specifiedPackages = null;
+ scheduledClasses = null;
+ sourcePath = null;
+ parser = null;
+ unlocatableReportedSet = null;
+ inaccessibleReportedSet = null;
+ }
+
+ public void setSourceEncoding(String sourceEncoding)
+ {
+ this.sourceEncoding = sourceEncoding;
+ }
+
+ public RootDocImpl()
+ {
+ super(null);
+ }
+
+ public static String readHtmlBody(File file)
+ throws IOException
+ {
+ FileReader fr=new FileReader(file);
+ long size = file.length();
+ char[] packageDocBuf=new char[(int)(size)];
+ int index = 0;
+ int i = fr.read(packageDocBuf, index, (int)size);
+ while (i > 0) {
+ index += i;
+ size -= i;
+ i = fr.read(packageDocBuf, index, (int)size);
+ }
+ fr.close();
+
+ // We only need the part between the begin and end body tag.
+ String html = new String(packageDocBuf);
+ int start = html.indexOf("<body");
+ if (start == -1)
+ start = html.indexOf("<BODY");
+ int end = html.indexOf("</body>");
+ if (end == -1)
+ end = html.indexOf("</BODY>");
+ if (start != -1 && end != -1) {
+ // Start is end of body tag.
+ start = html.indexOf('>', start) + 1;
+ if (start != -1 && start < end)
+ html = html.substring(start, end);
+ }
+ return html.trim();
+ }
+
+ public Parser getParser()
+ {
+ return parser;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SeeTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SeeTagImpl.java
new file mode 100644
index 000000000..12e2256dc
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SeeTagImpl.java
@@ -0,0 +1,215 @@
+/* gnu.classpath.tools.gjdoc.SeeTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+
+public class SeeTagImpl extends AbstractTagImpl implements SeeTag {
+
+ protected String reference;
+ private String referencedClassName;
+ private String referencedMemberName;
+ private ClassDoc referencedClass;
+ private MemberDoc referencedMember;
+ private PackageDoc referencedPackage;
+ private String label;
+ private ClassDocImpl contextClass;
+
+ public SeeTagImpl(String text, ClassDocImpl contextClass) {
+ super(text);
+ this.contextClass=contextClass;
+ }
+
+ public void resolve() {
+
+ super.resolve();
+
+ text = text.trim();
+
+ if (text.startsWith("<") || text.startsWith("\"")) {
+ label = text;
+ return;
+ }
+
+ int labelNdx=text.indexOf(';');
+ if (labelNdx>=0) {
+ label="";
+ return;
+ }
+
+ for (int i=0; i<text.length(); ++i) {
+ if (" \t\r\n".indexOf(text.charAt(i)) >= 0) {
+ labelNdx = i;
+ break;
+ }
+ }
+
+ int openParenNdx = text.indexOf('(');
+ if (openParenNdx >= 0 && openParenNdx < labelNdx) {
+ labelNdx=text.indexOf(')', openParenNdx);
+ if (labelNdx >= 0) {
+ ++ labelNdx;
+ }
+ }
+
+ if (labelNdx<0 || labelNdx>=text.length()) {
+ reference=text.trim();
+ label="";
+ }
+ else {
+ reference=text.substring(0,labelNdx).trim();
+ label=text.substring(labelNdx).trim();
+ }
+
+ int mspecNdx=reference.indexOf('#');
+ String referencedFqName;
+ if (mspecNdx<0) {
+ referencedFqName=reference;
+ }
+ else {
+ referencedFqName=reference.substring(0,mspecNdx);
+ referencedMemberName=reference.substring(mspecNdx+1);
+ }
+
+ // the following is in contradiction to the api docs, but
+ // conform to sun javadoc: return fully qualified classname
+ // with referencedClassName().
+ if (referencedFqName.trim().length()>0) {
+ referencedClassName=referencedFqName;
+ if (contextClass==null)
+ referencedClass=Main.getRootDoc().classNamed(referencedFqName);
+ else
+ referencedClass=contextClass.findClass(referencedFqName);
+ }
+ else {
+ referencedClassName="";
+ referencedClass=contextClass;
+ }
+
+ if (referencedClass==null) {
+ referencedClass = Main.getRootDoc().classNamed("java.lang." + referencedFqName);
+ }
+
+ if (referencedClass!=null && !referencedClass.isIncluded()) referencedClass=null;
+
+ if (referencedClass!=null) {
+ referencedPackage=referencedClass.containingPackage();
+ referencedClassName=referencedClass.qualifiedName();
+
+ if (referencedMemberName!=null) {
+
+ if (referencedMemberName.indexOf('(')<0) {
+ referencedMember=((ClassDocImpl)referencedClass).findFieldRec(referencedMemberName);
+ if (null == referencedMember) {
+ MethodDoc[] methods = ((ClassDocImpl)referencedClass).methods();
+ for (int i=0; i<methods.length; ++i) {
+ if (methods[i].name().equals(referencedMemberName)) {
+ if (null == referencedMember) {
+ referencedMember = methods[i];
+ }
+ else {
+ referencedClass = null;
+ referencedMember = null;
+ //print warning here
+ break;
+ }
+ }
+ }
+ }
+ else {
+ referencedClass = referencedMember.containingClass();
+ }
+ }
+ else {
+ referencedMember=((ClassDocImpl)referencedClass).findExecutableRec(referencedMemberName);
+ if (referencedMember==null) {
+ //System.err.println("cannot find member for '"+referencedMemberName+"'");
+ referencedClass = null;
+ }
+ }
+ }
+ }
+ /*
+ else {
+ System.err.println("class not found: '"+referencedFqName + "' in context class " + contextClass + " in " + this);
+ }
+ */
+ }
+
+ public ClassDoc referencedClass() {
+ return referencedClass;
+ }
+
+ public String referencedClassName() {
+ return referencedClassName;
+ }
+
+ public MemberDoc referencedMember() {
+ return referencedMember;
+ }
+
+ public String referencedMemberName() {
+ return referencedMemberName;
+ }
+
+ public PackageDoc referencedPackage() {
+ return referencedPackage;
+ }
+
+ public String label() {
+ return label;
+ }
+
+ public String kind() {
+ return "@see";
+ }
+
+ public String name() {
+ return "@see";
+ }
+
+ public Tag[] firstSentenceTags() {
+ return inlineTags();
+ }
+
+ public Tag[] inlineTags() {
+ return new Tag[]{new TextTagImpl(referencedClassName)};
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SerialFieldTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SerialFieldTagImpl.java
new file mode 100644
index 000000000..0ecfe637c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SerialFieldTagImpl.java
@@ -0,0 +1,128 @@
+/* gnu.classpath.tools.gjdoc.SerialFieldTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+
+public class SerialFieldTagImpl extends AbstractTagImpl implements SerialFieldTag {
+
+ private String fieldName;
+ private String fieldType;
+ private String description;
+ private ClassDoc fieldTypeDoc;
+ private ClassDocImpl contextClass;
+
+ public SerialFieldTagImpl(String text,
+ ClassDocImpl contextClass,
+ MemberDocImpl contextMember) {
+ super(text);
+ this.contextClass=contextClass;
+
+ if (fieldName==null)
+ fieldName="";
+ if (fieldType==null)
+ fieldType="";
+ if (description==null)
+ description="";
+
+ int state=1;
+ char[] textArr=text.toCharArray();
+ for (int i=0; i<textArr.length; ++i) {
+ char c=textArr[i];
+ switch (state) {
+ case 1:
+ if (Parser.isWhitespace(c)) state=2;
+ else fieldName+=c;
+ break;
+ case 2:
+ if (Parser.isWhitespace(c)) state=3;
+ else fieldType+=c;
+ break;
+ case 3:
+ description+=c;
+ break;
+ }
+ }
+
+ setBody(description, contextClass, contextMember);
+
+ }
+
+ public void resolve() {
+
+ super.resolve();
+ try {
+ Type type=contextClass.typeForString(fieldType);
+ this.fieldTypeDoc=type.asClassDoc();
+ } catch (ParseException e) {
+ System.err.println("FIXME: add try-catch to force compilation"
+ + e);
+ }
+ }
+
+ public ClassDoc fieldTypeDoc() {
+ return fieldTypeDoc;
+ }
+
+ public String fieldName() {
+ return fieldName;
+ }
+
+ public String fieldType() {
+ return fieldType;
+ }
+
+ public String description() {
+ return description;
+ }
+
+ public String kind() {
+ return "@serialField";
+ }
+
+ public int compareTo(Object o) {
+ if (o!=null && o instanceof SerialFieldTagImpl) {
+ return fieldName().compareTo(((SerialFieldTagImpl)o).fieldName());
+ }
+ else {
+ return 0;
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SourcePositionImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SourcePositionImpl.java
new file mode 100644
index 000000000..e2d73bbd5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/SourcePositionImpl.java
@@ -0,0 +1,77 @@
+/* gnu.classpath.tools.gjdoc.SourcePositionImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.SourcePosition;
+
+import java.io.File;
+
+public class SourcePositionImpl
+ implements SourcePosition
+{
+ private File file;
+ private int line;
+ private int column;
+
+ public SourcePositionImpl(File file, int line, int column)
+ {
+ this.file = file;
+ this.line = line;
+ this.column = column;
+ }
+
+ public File file()
+ {
+ return this.file;
+ }
+
+ public int line()
+ {
+ return this.line;
+ }
+
+ public int column()
+ {
+ return this.column;
+ }
+
+ public String toString()
+ {
+ return this.file + ":" + this.line;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagContainer.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagContainer.java
new file mode 100644
index 000000000..1b9bc40d9
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagContainer.java
@@ -0,0 +1,52 @@
+/* gnu.classpath.tools.gjdoc.TagContainer
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.Tag;
+
+import java.util.Map;
+
+/**
+ * Implemented by Doclet API classes that are associated with tags.
+ */
+interface TagContainer
+{
+ public Tag[] firstSentenceTags();
+ public Tag[] inlineTags();
+ public Map getTagMap();
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagImpl.java
new file mode 100644
index 000000000..a4b1f4b2a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TagImpl.java
@@ -0,0 +1,60 @@
+/* gnu.classpath.tools.gjdoc.TagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+
+public class TagImpl extends AbstractTagImpl implements Tag {
+
+ private String kind;
+ private String name;
+
+ TagImpl(String name, String text, ClassDocImpl contextClass, MemberDocImpl contextMember) {
+ super(text);
+ this.kind=name;
+ this.name=name;
+
+ setBody(text, contextClass, contextMember);
+ }
+
+ public String kind() { return kind; }
+ public String name() { return name; }
+ public String toString() { return kind()+":"+text(); }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TemporaryStore.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TemporaryStore.java
new file mode 100644
index 000000000..0333ee2b7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TemporaryStore.java
@@ -0,0 +1,132 @@
+/* gnu.classpath.tools.gjdoc.TemporaryStore
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+/**
+ * Useful for passing big objects that are no longer needed by the
+ * calling method, reducing memory usage. <p/>
+ *
+ * Consider the following problem:
+ * <pre>
+ * public class A {
+ * public static void foo() {
+ * long[] hugeArray = new long[1000000]; // takes around 8 MB
+ * // ... fill hugeArray with some information ...
+ * bar(hugeArray);
+ * // ... hugeArray is no more required at this point
+ * }
+ * public static void bar(long[] arr) {
+ * // ... process contents of arr ...
+ * arr = null;
+ * System.gc(); // NOTE: will not collect arr!
+ * // ... do something memory-intensive where arr is not needed
+ * }
+ * }
+ * </pre>
+ *
+ * In method <code>bar()</code>, the array cannot be garbage
+ * collected because the local variable <code>hugeArray</code> in
+ * method <code>foo()</code> still holds a reference to the array.
+ * <p/>
+ *
+ * When calling <code>bar(new long[1000000]);</code> in
+ * <code>arr</code> the array <i>can</i> be collected in
+ * <code>bar()</code>, but that way it can't be initialized in
+ * <code>foo()</code>. A local variable is needed for
+ * initialization, but the variable can't be cleared before it is
+ * passed to <code>bar()</code>! <p/>
+ *
+ * <code>TemporaryStore</code> is the solution for this
+ * dilemma. The modified method <code>foo()</code> which uses a
+ * <code>TemporaryStore</code> object would look like this:
+ *
+ * <pre>
+ * public static void foo() {
+ * long[] hugeArray = new long[1000000]; // takes around 7 MB
+ * // ... fill hugeArray with some very important information ...
+ * TemporaryStore tstore = new TemporaryStore(hugeArray);
+ * hugeArray = null;
+ * bar((long[])tstore.getAndClear());
+ * }
+ * </pre>
+ *
+ * When control flow is transferred to <code>bar()</code>,
+ * <code>foo()</code> will hold no more references to the array
+ * and so it can be garbage collected in <code>bar()</code>.
+ *
+ */
+public class TemporaryStore {
+
+ private Object storedObject;
+
+ /**
+ * Temporarily store the given object for passing it to a
+ * different method. <p/>
+ *
+ * The method constructing a new TemporaryStore object should
+ * clear all other references to the stored object, so that
+ * this TemporaryStore is the only object referencing it.
+ *
+ * @param storedObject the object to store temporarily
+ *
+ */
+ public TemporaryStore(Object storedObject) {
+ this.storedObject = storedObject;
+ }
+
+ /**
+ * Return the stored object after clearing the reference to it.
+ * <p/>
+ *
+ * When the user of this class followed the recommendations in
+ * the documentation of @link{TemporaryStore(Object)}, the
+ * returned reference will be the only reference to the stored
+ * object after this method returns. If the returned reference
+ * is passed in a method call, the called method will hold the
+ * only reference to the stored object and can release it by
+ * nulling the corresponding parameter.
+ *
+ * @return the object which was passed to the constructor.
+ *
+ */
+ public Object getAndClear() {
+ Object rc = this.storedObject;
+ this.storedObject = null;
+ return rc;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TextTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TextTagImpl.java
new file mode 100644
index 000000000..812fd2fde
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TextTagImpl.java
@@ -0,0 +1,56 @@
+/* gnu.classpath.tools.gjdoc.TextTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+
+public class TextTagImpl extends AbstractTagImpl implements Tag {
+
+ TextTagImpl(String text) {
+ super(text);
+ }
+
+ public Tag[] firstSentenceTags() { return new Tag[]{this}; }
+ public Tag[] inlineTags() { return new Tag[]{this}; }
+ public String kind() { return "Text"; }
+
+ public String toString() { return "TextTagImpl{text=" + text + "}"; }
+
+ public String getText() { return text; }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ThrowsTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ThrowsTagImpl.java
new file mode 100644
index 000000000..e4e7bbfcb
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ThrowsTagImpl.java
@@ -0,0 +1,105 @@
+/* gnu.classpath.tools.gjdoc.ThrowsTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+
+public class ThrowsTagImpl extends AbstractTagImpl implements ThrowsTag {
+
+ private ClassDoc exception;
+ private String exceptionName;
+ private String exceptionComment;
+
+ public ThrowsTagImpl(String text,
+ ClassDocImpl contextClass,
+ MemberDocImpl contextMember) {
+ super(text);
+
+ char[] textarr=text.toCharArray();
+ int i=0;
+ for (; i<textarr.length; ++i) {
+ if (!Parser.isWhitespace(textarr[i])) break;
+ }
+ for (; i<textarr.length; ++i) {
+ if (Parser.isWhitespace(textarr[i])) {
+ this.exceptionName=new String(textarr,0,i).trim();
+ this.exceptionComment=new String(textarr,i,textarr.length-i).trim();
+ break;
+ }
+ }
+ if (null != exceptionName) {
+ if (contextClass==null) {
+ this.exception=Main.getRootDoc().classNamed(exceptionName);
+ }
+ else {
+ this.exception=contextClass.findClass(exceptionName);
+ }
+ if (exception!=null)
+ this.exceptionName=exception.qualifiedName();
+ else {
+ if (text.trim().startsWith("<")) {
+ Main.getRootDoc().printWarning("Expected exception name but got '"+text+"' in class "+contextClass.getClassName());
+ }
+ }
+ }
+ else {
+ Main.getRootDoc().printWarning("@throws tag in comment for " + contextClass.qualifiedName() + "." + contextMember.name() + " doesn't specify an exception.");
+ }
+ if (this.exceptionComment!=null) {
+ setBody(this.exceptionComment, contextClass, contextMember);
+ }
+ }
+
+ public ClassDoc exception() {
+ return exception;
+ }
+
+ public String exceptionName() {
+ return exceptionName;
+ }
+
+ public String exceptionComment() {
+ return exceptionComment;
+ }
+
+ public String kind() {
+ return "@throws";
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Timer.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Timer.java
new file mode 100644
index 000000000..93404d08e
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/Timer.java
@@ -0,0 +1,88 @@
+/* gnu.classpath.tools.gjdoc.Timer
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import java.io.*;
+import java.text.*;
+
+public class Timer {
+
+ private static long startTime, beforeDocletTime, stopTime, memoryUsed, maxDriverHeap=-1, maxDocletHeap=-1;
+
+ static void shutdown() {
+ try{
+ if (stopTime==0) return;
+ PrintWriter pw=new PrintWriter(new FileWriter("timer.out"));
+ pw.println("Preparation (driver) took "+(((double)(beforeDocletTime-startTime))/1000.)+" s");
+ pw.println("Generation (doclet) took "+(((double)(stopTime-beforeDocletTime))/1000.)+" s");
+ pw.println("");
+ pw.println("Memory used for documentation tree: "+(memoryUsed/(1024*1024))+" MB");
+ pw.println("Max. heap used for driver: "+((maxDriverHeap<0)?"N/A":((maxDriverHeap/(1024*1024))+" MB")));
+ pw.println("Max. heap used for doclet: "+((maxDocletHeap<0)?"N/A":((maxDocletHeap/(1024*1024))+" MB")));
+ pw.println("");
+ pw.println("TOTAL TIME: "+(((double)(stopTime-startTime))/1000.)+" s");
+ pw.println("TOTAL HEAP: "+((maxDocletHeap<0)?"N/A":(Math.max(maxDocletHeap,maxDriverHeap)/(1024*1024))+" MB"));
+ pw.close();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void setStartTime() {
+ Timer.startTime=System.currentTimeMillis();
+ }
+
+ public static void setStopTime() {
+ Timer.stopTime=System.currentTimeMillis();
+ }
+
+ public static void setBeforeDocletTime() {
+ Timer.beforeDocletTime=System.currentTimeMillis();
+ Timer.memoryUsed=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
+ }
+
+ public static void setMaxDocletHeap(long maximumHeap) {
+ Timer.maxDocletHeap=maximumHeap;
+ }
+
+ public static void setMaxDriverHeap(long maximumHeap) {
+ Timer.maxDriverHeap=maximumHeap;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TimerDoclet.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TimerDoclet.java
new file mode 100644
index 000000000..c2c3c3edf
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TimerDoclet.java
@@ -0,0 +1,104 @@
+/* gnu.classpath.tools.gjdoc.TimerDoclet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+
+public class TimerDoclet {
+
+ private static Object doclet = null;
+
+ private static long maximumHeap = -1;
+
+ private static Thread memThread;
+
+ private static boolean runMemThread = true;
+
+ private static void init() throws Exception {
+ if (doclet==null) {
+ doclet=Class.forName("com.sun.tools.doclets.standard.Standard").newInstance();
+ memThread=new Thread() {
+
+ public void run() {
+ while (runMemThread) {
+ synchronized (TimerDoclet.class) {
+ TimerDoclet.maximumHeap=Math.max(TimerDoclet.maximumHeap,
+ Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());
+ }
+ try { Thread.sleep(50); } catch (Exception e) {}
+ }
+ }
+ };
+ //memThread.start();
+ }
+ }
+
+ public static boolean validOptions(String[][] options, DocErrorReporter reporter)
+ throws Exception {
+
+ init();
+ return ((Boolean)doclet.getClass().getMethod("validOptions", new Class[]{String[][].class, DocErrorReporter.class}).invoke(null, new Object[]{options, reporter})).booleanValue();
+ //return false; //doclet.validOptions(options, reporter);
+ }
+
+ public static int optionLength(String option) throws Exception {
+ init();
+ return ((Integer)doclet.getClass().getMethod("optionLength", new Class[]{String.class}).invoke(null, new Object[]{option})).intValue();
+ }
+
+ public static boolean start(RootDoc root) throws Exception {
+ Timer.setBeforeDocletTime();
+ synchronized (TimerDoclet.class) {
+ Timer.setMaxDriverHeap(maximumHeap);
+ maximumHeap=-1;
+ }
+ //new com.sun.tools.doclets.standard.Standard().validOptions(root.options(), root);
+ //new com.sun.tools.doclets.standard.Standard().start(root);
+
+ if (validOptions(root.options(), root)) {
+ doclet.getClass().getMethod("start", new Class[]{RootDoc.class}).invoke(null, new Object[]{root});
+ }
+ runMemThread=false;
+ Timer.setStopTime();
+ synchronized (TimerDoclet.class) {
+ Timer.setMaxDocletHeap(maximumHeap);
+ }
+ Timer.shutdown();
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeImpl.java
new file mode 100644
index 000000000..8c1bd5a0d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeImpl.java
@@ -0,0 +1,109 @@
+/* gnu.classpath.tools.gjdoc.TypeImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+
+public class TypeImpl implements Type, WritableType {
+
+ private String packageName;
+ private String typeName;
+ private String dimension;
+
+ TypeImpl(String packageName, String typeName, String dimension) {
+ this.packageName=packageName;
+ this.typeName=typeName;
+ this.dimension=dimension;
+
+ if (typeName.indexOf('[') >= 0 || typeName.indexOf(']') >= 0) {
+ throw new RuntimeException("Typename must not contain dimension information.");
+ }
+ }
+
+ public ClassDoc asClassDoc() {
+
+ if (this instanceof ClassDoc)
+ return ((ClassDocImpl)(ClassDoc)this).getBaseClassDoc();
+ else
+ return null;
+ }
+
+ public String typeName() { return typeName; }
+
+ public String qualifiedTypeName() { return (packageName!=null)?(packageName+"."+typeName):(typeName); }
+
+ public String dimension() { return dimension; }
+ public void setDimension(String dimension) { this.dimension = dimension; }
+
+ public String toString() { return "Type{"+qualifiedTypeName()+dimension()+"}"; }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ public boolean isPrimitive()
+ {
+ return null == packageName && primitiveNames.contains(typeName);
+ }
+
+ private static final Set primitiveNames;
+ static {
+ Set _primitiveNames = new HashSet();
+ _primitiveNames.add("boolean");
+ _primitiveNames.add("char");
+ _primitiveNames.add("byte");
+ _primitiveNames.add("short");
+ _primitiveNames.add("int");
+ _primitiveNames.add("long");
+ _primitiveNames.add("float");
+ _primitiveNames.add("double");
+ primitiveNames = Collections.unmodifiableSet(_primitiveNames);
+ }
+
+ public TypeVariable asTypeVariable()
+ {
+ if (this instanceof TypeVariable)
+ return (TypeVariable) this;
+ else
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeVariableImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeVariableImpl.java
new file mode 100644
index 000000000..08a236683
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/TypeVariableImpl.java
@@ -0,0 +1,108 @@
+/* gnu.classpath.tools.gjdoc.TypeVariableImpl
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.ProgramElementDoc;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+
+import java.util.List;
+
+public class TypeVariableImpl
+ extends TypeImpl
+ implements TypeVariable, WritableType
+{
+
+ /**
+ * The bounds of this particular type variable.
+ */
+ Type[] bounds;
+
+ /**
+ * The owning program element of this type variable.
+ */
+ ProgramElementDoc owner;
+
+ /**
+ * Constructs a new type variable with the supplied name and owner.
+ *
+ * @param packageName the name of the package containing the type variable.
+ * @param typeName the name of the type variable.
+ * @param dimension the dimensions of the type variable (always "").
+ * @param owner the owning program element of the type variable.
+ */
+ TypeVariableImpl(String packageName, String typeName, String dimension,
+ ProgramElementDoc owner)
+ {
+ super(packageName, typeName, dimension);
+ this.owner = owner;
+ }
+
+ /**
+ * Set the bounds to the contents of the supplied list.
+ *
+ * @param parsedBounds a list of type bounds.
+ */
+ void setBounds(List parsedBounds)
+ {
+ bounds = (Type[]) parsedBounds.toArray(new Type[parsedBounds.size()]);
+ }
+
+ /**
+ * Returns the bounds of this type variable.
+ *
+ * @return the bounds of the variable.
+ */
+ public Type[] bounds()
+ {
+ return bounds;
+ }
+
+ /**
+ * Returns the owning program element for this type variable.
+ *
+ * @return the owning program element, whether a class, interface,
+ * constructor or method.
+ */
+ public ProgramElementDoc owner()
+ {
+ return owner;
+ }
+
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ValueTagImpl.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ValueTagImpl.java
new file mode 100644
index 000000000..024594c6a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/ValueTagImpl.java
@@ -0,0 +1,65 @@
+/* gnu.classpath.tools.gjdoc.ValueTagImpl
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+import com.sun.javadoc.*;
+import java.util.*;
+import java.text.*;
+
+public class ValueTagImpl extends SeeTagImpl {
+
+ public ValueTagImpl(String _text, ClassDocImpl contextClass) {
+ super(_text, contextClass);
+ }
+
+ public String name() { return "@value"; }
+
+ public Tag[] firstSentenceTags() {
+ return inlineTags();
+ }
+
+ public Tag[] inlineTags() {
+ if (null != reference && reference.trim().length() > 0) {
+ return new Tag[] { new TextTagImpl(reference) };
+ }
+ else {
+ return new Tag[0];
+ }
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/WritableType.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/WritableType.java
new file mode 100644
index 000000000..39cfb3f25
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/WritableType.java
@@ -0,0 +1,44 @@
+/* gnu.classpath.tools.gjdoc.WritableType
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc;
+
+public interface WritableType extends Cloneable {
+
+ public void setDimension(String dimension);
+ public Object clone() throws CloneNotSupportedException;
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AdditionExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AdditionExpression.java
new file mode 100644
index 000000000..82502c431
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AdditionExpression.java
@@ -0,0 +1,86 @@
+/* gnu.classpath.tools.gjdoc.expr.AdditionExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class AdditionExpression
+ extends BinaryComputationExpression
+{
+ public AdditionExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected double compute(double leftValue, double rightValue)
+ {
+ return leftValue + rightValue;
+ }
+
+ protected float compute(float leftValue, float rightValue)
+ {
+ return leftValue + rightValue;
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue + rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue + rightValue;
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression leftValue = left.evaluate(context);
+ ConstantExpression rightValue = right.evaluate(context);
+
+ if (Type.STRING == leftValue.getType()
+ || Type.STRING == rightValue.getType()) {
+
+ return new ConstantString(leftValue.asObject().toString()
+ + rightValue.asObject().toString());
+ }
+ else {
+ return super.evaluate(leftValue, rightValue);
+ }
+
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AndExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AndExpression.java
new file mode 100644
index 000000000..ac807728b
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/AndExpression.java
@@ -0,0 +1,57 @@
+/* gnu.classpath.tools.gjdoc.expr.AndExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class AndExpression
+ extends BinaryBitwiseExpression
+{
+ public AndExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue & rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue & rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryBitwiseExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryBitwiseExpression.java
new file mode 100644
index 000000000..3c44ce7d8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryBitwiseExpression.java
@@ -0,0 +1,68 @@
+/* gnu.classpath.tools.gjdoc.expr.BinaryBitwiseExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class BinaryBitwiseExpression
+ extends BinaryExpression
+{
+ protected BinaryBitwiseExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression leftValue = left.evaluate(context);
+ ConstantExpression rightValue = right.evaluate(context);
+
+ if (Type.LONG == leftValue.getType()
+ || Type.LONG == rightValue.getType()) {
+
+ return new ConstantLong(compute(leftValue.asNumber().longValue(),
+ rightValue.asNumber().longValue()));
+ }
+ else {
+ return new ConstantInteger(compute(leftValue.asNumber().intValue(),
+ rightValue.asNumber().intValue()));
+ }
+ }
+
+ protected abstract long compute(long leftValue, long rightValue);
+ protected abstract int compute(int leftValue, int rightValue);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryComputationExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryComputationExpression.java
new file mode 100644
index 000000000..15d016e1f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryComputationExpression.java
@@ -0,0 +1,92 @@
+/* gnu.classpath.tools.gjdoc.expr.BinaryComputationExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class BinaryComputationExpression
+ extends BinaryExpression
+{
+ protected BinaryComputationExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression leftValue = left.evaluate(context);
+ ConstantExpression rightValue = right.evaluate(context);
+
+ return evaluate(leftValue, rightValue);
+ }
+
+ protected ConstantExpression evaluate(ConstantExpression leftValue,
+ ConstantExpression rightValue)
+ throws IllegalExpressionException
+ {
+ if (Type.DOUBLE == leftValue.getType()
+ || Type.DOUBLE == rightValue.getType()) {
+
+ return new ConstantDouble(compute(leftValue.asNumber().doubleValue(),
+ rightValue.asNumber().doubleValue()));
+ }
+ else if (Type.FLOAT == leftValue.getType()
+ || Type.FLOAT == rightValue.getType()) {
+
+ return new ConstantFloat(compute(leftValue.asNumber().floatValue(),
+ rightValue.asNumber().floatValue()));
+ }
+ else if (Type.LONG == leftValue.getType()
+ || Type.LONG == rightValue.getType()) {
+
+ return new ConstantLong(compute(leftValue.asNumber().longValue(),
+ rightValue.asNumber().longValue()));
+ }
+ else if (leftValue.isNumber() && rightValue.isNumber()) {
+ return new ConstantInteger(compute(leftValue.asNumber().intValue(),
+ rightValue.asNumber().intValue()));
+ }
+ else {
+ throw new IllegalExpressionException("Operator ? cannot be applied to " + leftValue.getType() + "," + rightValue.getType());
+ }
+ }
+
+ protected abstract double compute(double leftValue, double rightValue);
+ protected abstract float compute(float leftValue, float rightValue);
+ protected abstract long compute(long leftValue, long rightValue);
+ protected abstract int compute(int leftValue, int rightValue);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryEqualityExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryEqualityExpression.java
new file mode 100644
index 000000000..1b37c233a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryEqualityExpression.java
@@ -0,0 +1,89 @@
+/* gnu.classpath.tools.gjdoc.expr.BinaryEqualityExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class BinaryEqualityExpression
+ extends BinaryExpression
+{
+ protected BinaryEqualityExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression leftValue = left.evaluate(context);
+ ConstantExpression rightValue = right.evaluate(context);
+
+ if (Type.DOUBLE == leftValue.getType()
+ || Type.DOUBLE == rightValue.getType()) {
+
+ return new ConstantBoolean(compute(leftValue.asNumber().doubleValue(),
+ rightValue.asNumber().doubleValue()));
+ }
+ else if (Type.FLOAT == leftValue.getType()
+ || Type.FLOAT == rightValue.getType()) {
+
+ return new ConstantBoolean(compute(leftValue.asNumber().floatValue(),
+ rightValue.asNumber().floatValue()));
+ }
+ else if (Type.LONG == leftValue.getType()
+ || Type.LONG == rightValue.getType()) {
+
+ return new ConstantBoolean(compute(leftValue.asNumber().longValue(),
+ rightValue.asNumber().longValue()));
+ }
+ else if (Type.BOOLEAN == leftValue.getType()
+ && Type.BOOLEAN == rightValue.getType()) {
+
+ return new ConstantBoolean(compute(((ConstantBoolean)leftValue).booleanValue(),
+ ((ConstantBoolean)rightValue).booleanValue()));
+ }
+ else {
+ return new ConstantBoolean(compute(leftValue.asNumber().intValue(),
+ rightValue.asNumber().intValue()));
+ }
+ }
+
+ protected abstract boolean compute(double leftValue, double rightValue);
+ protected abstract boolean compute(float leftValue, float rightValue);
+ protected abstract boolean compute(long leftValue, long rightValue);
+ protected abstract boolean compute(int leftValue, int rightValue);
+ protected abstract boolean compute(boolean leftValue, boolean rightValue);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryExpression.java
new file mode 100644
index 000000000..557b514c7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryExpression.java
@@ -0,0 +1,51 @@
+/* gnu.classpath.tools.gjdoc.expr.BinaryExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class BinaryExpression
+ implements Expression
+{
+ protected Expression left;
+ protected Expression right;
+
+ protected BinaryExpression(Expression left, Expression right)
+ {
+ this.left = left;
+ this.right = right;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryLogicalExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryLogicalExpression.java
new file mode 100644
index 000000000..7fa51869c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryLogicalExpression.java
@@ -0,0 +1,64 @@
+/* gnu.classpath.tools.gjdoc.expr.BinaryLogicalExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class BinaryLogicalExpression
+ extends BinaryExpression
+{
+ protected BinaryLogicalExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression leftValue = left.evaluate(context);
+ ConstantExpression rightValue = right.evaluate(context);
+
+ if (leftValue.getType() != Type.BOOLEAN || rightValue.getType() != Type.BOOLEAN) {
+ throw new IllegalExpressionException("logical expression expects boolean subexpressions");
+ }
+ else {
+ return new ConstantBoolean(compute(((ConstantBoolean)leftValue).booleanValue(),
+ ((ConstantBoolean)rightValue).booleanValue()));
+ }
+ }
+
+ protected abstract boolean compute(boolean leftValue, boolean rightValue);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryRelationExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryRelationExpression.java
new file mode 100644
index 000000000..f6ef45cf5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryRelationExpression.java
@@ -0,0 +1,82 @@
+/* gnu.classpath.tools.gjdoc.expr.BinaryRelationExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class BinaryRelationExpression
+ extends BinaryExpression
+{
+ protected BinaryRelationExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression leftValue = left.evaluate(context);
+ ConstantExpression rightValue = right.evaluate(context);
+
+ if (Type.DOUBLE == leftValue.getType()
+ || Type.DOUBLE == rightValue.getType()) {
+
+ return new ConstantBoolean(compute(leftValue.asNumber().doubleValue(),
+ rightValue.asNumber().doubleValue()));
+ }
+ else if (Type.FLOAT == leftValue.getType()
+ || Type.FLOAT == rightValue.getType()) {
+
+ return new ConstantBoolean(compute(leftValue.asNumber().floatValue(),
+ rightValue.asNumber().floatValue()));
+ }
+ else if (Type.LONG == leftValue.getType()
+ || Type.LONG == rightValue.getType()) {
+
+ return new ConstantBoolean(compute(leftValue.asNumber().longValue(),
+ rightValue.asNumber().longValue()));
+ }
+ else {
+ return new ConstantBoolean(compute(leftValue.asNumber().intValue(),
+ rightValue.asNumber().intValue()));
+ }
+ }
+
+ protected abstract boolean compute(double leftValue, double rightValue);
+ protected abstract boolean compute(float leftValue, float rightValue);
+ protected abstract boolean compute(long leftValue, long rightValue);
+ protected abstract boolean compute(int leftValue, int rightValue);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryShiftExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryShiftExpression.java
new file mode 100644
index 000000000..32ccea209
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BinaryShiftExpression.java
@@ -0,0 +1,66 @@
+/* gnu.classpath.tools.gjdoc.expr.BinaryShiftExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class BinaryShiftExpression
+ extends BinaryExpression
+{
+ protected BinaryShiftExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression leftValue = left.evaluate(context);
+ ConstantExpression rightValue = right.evaluate(context);
+
+ if (Type.LONG == leftValue.getType()) {
+ return new ConstantLong(compute(leftValue.asNumber().longValue(),
+ rightValue.asNumber().intValue()));
+ }
+ else {
+ return new ConstantInteger(compute(leftValue.asNumber().intValue(),
+ rightValue.asNumber().intValue()));
+ }
+ }
+
+ protected abstract long compute(long leftValue, int rightValue);
+ protected abstract int compute(int leftValue, int rightValue);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BitShiftRightExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BitShiftRightExpression.java
new file mode 100644
index 000000000..eca1a5257
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/BitShiftRightExpression.java
@@ -0,0 +1,57 @@
+/* gnu.classpath.tools.gjdoc.expr.BitShiftRightExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class BitShiftRightExpression
+ extends BinaryShiftExpression
+{
+ public BitShiftRightExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected long compute(long leftValue, int rightValue)
+ {
+ return leftValue >>> rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue >>> rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/CircularExpressionException.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/CircularExpressionException.java
new file mode 100644
index 000000000..a9bfacc89
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/CircularExpressionException.java
@@ -0,0 +1,52 @@
+/* gnu.classpath.tools.gjdoc.expr.IllegalExpressionException
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+public class CircularExpressionException
+ extends IllegalExpressionException
+{
+ public CircularExpressionException(String message)
+ {
+ super(message);
+ }
+
+ public CircularExpressionException(Throwable cause)
+ {
+ super(cause);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConditionalExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConditionalExpression.java
new file mode 100644
index 000000000..d9532efb0
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConditionalExpression.java
@@ -0,0 +1,74 @@
+/* gnu.classpath.tools.gjdoc.expr.ConditionalExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConditionalExpression
+ implements Expression
+{
+ private Expression condition;
+ private Expression ifTrue;
+ private Expression ifFalse;
+
+ ConditionalExpression(Expression condition, Expression ifTrue, Expression ifFalse)
+ {
+ this.condition = condition;
+ this.ifTrue = ifTrue;
+ this.ifFalse = ifFalse;
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression conditionValue = condition.evaluate(context);
+ ConstantExpression ifTrueValue = ifTrue.evaluate(context);
+ ConstantExpression ifFalseValue = ifFalse.evaluate(context);
+
+ if (Type.BOOLEAN != conditionValue.getType()) {
+ throw new IllegalExpressionException("condition must be boolean");
+ }
+ else {
+ boolean cond = ((ConstantBoolean)conditionValue).booleanValue();
+ if (cond) {
+ return ifTrueValue;
+ }
+ else {
+ return ifFalseValue;
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantBoolean.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantBoolean.java
new file mode 100644
index 000000000..83faf1f20
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantBoolean.java
@@ -0,0 +1,84 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantBoolean
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantBoolean
+ extends ConstantExpression
+{
+ private boolean value;
+
+ public ConstantBoolean(String stringValue)
+ {
+ this.value = "true".equals(stringValue);
+ }
+
+ public ConstantBoolean(boolean booleanValue)
+ {
+ this.value = booleanValue;
+ }
+
+ public boolean booleanValue()
+ {
+ return value;
+ }
+
+ public Type getType()
+ {
+ return Type.BOOLEAN;
+ }
+
+ public Number asNumber()
+ {
+ return null;
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public Object asObject()
+ {
+ return new Boolean(value);
+ }
+
+ public String toString()
+ {
+ return Boolean.toString(value);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantByte.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantByte.java
new file mode 100644
index 000000000..e206e567f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantByte.java
@@ -0,0 +1,74 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantByte
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantByte
+ extends ConstantExpression
+{
+ private byte value;
+
+ public ConstantByte(byte byteValue)
+ {
+ this.value = byteValue;
+ }
+
+ public Type getType()
+ {
+ return Type.BYTE;
+ }
+
+ public Number asNumber()
+ {
+ return new Byte(value);
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public Object asObject()
+ {
+ return asNumber();
+ }
+
+ public String toString()
+ {
+ return Byte.toString(value);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantChar.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantChar.java
new file mode 100644
index 000000000..3cbeac126
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantChar.java
@@ -0,0 +1,98 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantChar
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantChar
+ extends ConstantExpression
+{
+ private char value;
+
+ public ConstantChar(String stringValue)
+ {
+ this.value = stringValue.charAt(1); // FIXME
+ if (value == '\\') {
+ switch (stringValue.charAt(2)) {
+ case 'n': value = '\n'; break;
+ case 't': value = '\t'; break;
+ case 'f': value = '\f'; break;
+ case 'r': value = '\r'; break;
+ case 'b': value = '\b'; break;
+ case 'u':
+ {
+ String stringVal = stringValue.substring(3, stringValue.length() - 1);
+ /*
+ while (stringVal.length() > 1 && stringVal.charAt(0) == '0') {
+ stringVal = stringVal.substring(1);
+ }
+ */
+ value = (char)Integer.parseInt(stringVal, 16); break;
+ }
+ }
+ }
+ }
+
+ public ConstantChar(char charValue)
+ {
+ this.value = charValue;
+ }
+
+ public Type getType()
+ {
+ return Type.CHAR;
+ }
+
+ public Number asNumber()
+ {
+ return new Integer((int)value);
+ }
+
+ public Object asObject()
+ {
+ return new Character(value);
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public String toString()
+ {
+ return Character.toString(value);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantDouble.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantDouble.java
new file mode 100644
index 000000000..5faa5a17b
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantDouble.java
@@ -0,0 +1,79 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantDouble
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantDouble
+ extends ConstantExpression
+{
+ private double value;
+
+ public ConstantDouble(String stringValue)
+ {
+ this.value = Double.parseDouble(stringValue);
+ }
+
+ public ConstantDouble(double doubleValue)
+ {
+ this.value = doubleValue;
+ }
+
+ public Type getType()
+ {
+ return Type.DOUBLE;
+ }
+
+ public Number asNumber()
+ {
+ return new Double(value);
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public Object asObject()
+ {
+ return asNumber();
+ }
+
+ public String toString()
+ {
+ return Double.toString(value);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantExpression.java
new file mode 100644
index 000000000..93923e6ae
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantExpression.java
@@ -0,0 +1,52 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class ConstantExpression
+ implements Expression
+{
+ public abstract Type getType();
+ public abstract Number asNumber();
+ public abstract Object asObject();
+ public abstract boolean isNumber();
+
+ public ConstantExpression evaluate(Context context)
+ {
+ return this;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantFloat.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantFloat.java
new file mode 100644
index 000000000..46895500d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantFloat.java
@@ -0,0 +1,79 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantFloat
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantFloat
+ extends ConstantExpression
+{
+ private float value;
+
+ public ConstantFloat(String stringValue)
+ {
+ this.value = Float.parseFloat(stringValue);
+ }
+
+ public ConstantFloat(float floatValue)
+ {
+ this.value = floatValue;
+ }
+
+ public Type getType()
+ {
+ return Type.FLOAT;
+ }
+
+ public Number asNumber()
+ {
+ return new Float(value);
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public Object asObject()
+ {
+ return asNumber();
+ }
+
+ public String toString()
+ {
+ return "ConstantFloat{" + value + "}";
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantInteger.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantInteger.java
new file mode 100644
index 000000000..10804a695
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantInteger.java
@@ -0,0 +1,79 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantInteger
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantInteger
+ extends ConstantExpression
+{
+ private long value;
+
+ public ConstantInteger(String stringValue)
+ {
+ this.value = Evaluator.parseLong(stringValue);
+ }
+
+ public ConstantInteger(int integerValue)
+ {
+ this.value = integerValue;
+ }
+
+ public Type getType()
+ {
+ return Type.INTEGER;
+ }
+
+ public Number asNumber()
+ {
+ return new Long(value);
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public Object asObject()
+ {
+ return new Integer((int)value);
+ }
+
+ public String toString()
+ {
+ return Long.toString(value);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantLong.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantLong.java
new file mode 100644
index 000000000..a0a2f4b80
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantLong.java
@@ -0,0 +1,84 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantLong
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantLong
+ extends ConstantExpression
+{
+ private long value;
+
+ public ConstantLong(String stringValue)
+ {
+ if ('l' == Character.toLowerCase(stringValue.charAt(stringValue.length() - 1))) {
+ this.value = Evaluator.parseLong(stringValue.substring(0, stringValue.length() - 1));
+ }
+ else {
+ this.value = Evaluator.parseInt(stringValue.substring(0, stringValue.length() - 1));
+ }
+ }
+
+ public ConstantLong(long longValue)
+ {
+ this.value = longValue;
+ }
+
+ public Type getType()
+ {
+ return Type.LONG;
+ }
+
+ public Number asNumber()
+ {
+ return new Long(value);
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public Object asObject()
+ {
+ return asNumber();
+ }
+
+ public String toString()
+ {
+ return Long.toString(value);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantNull.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantNull.java
new file mode 100644
index 000000000..c27b10b8a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantNull.java
@@ -0,0 +1,66 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantNull
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantNull
+ extends ConstantExpression
+{
+ public ConstantNull()
+ {
+ }
+
+ public Type getType()
+ {
+ return Type.NULL;
+ }
+
+ public Number asNumber()
+ {
+ return null;
+ }
+
+ public boolean isNumber()
+ {
+ return false;
+ }
+
+ public Object asObject()
+ {
+ return null;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantShort.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantShort.java
new file mode 100644
index 000000000..5f4f00e1c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantShort.java
@@ -0,0 +1,74 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantShort
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantShort
+ extends ConstantExpression
+{
+ private short value;
+
+ public ConstantShort(short shortValue)
+ {
+ this.value = shortValue;
+ }
+
+ public Type getType()
+ {
+ return Type.SHORT;
+ }
+
+ public Number asNumber()
+ {
+ return new Short(value);
+ }
+
+ public boolean isNumber()
+ {
+ return true;
+ }
+
+ public Object asObject()
+ {
+ return asNumber();
+ }
+
+ public String toString()
+ {
+ return Short.toString(value);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantString.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantString.java
new file mode 100644
index 000000000..4e9ecdee1
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ConstantString.java
@@ -0,0 +1,74 @@
+/* gnu.classpath.tools.gjdoc.expr.ConstantString
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ConstantString
+ extends ConstantExpression
+{
+ private String value;
+
+ public ConstantString(String value)
+ {
+ this.value = value;
+ }
+
+ public Type getType()
+ {
+ return Type.STRING;
+ }
+
+ public Number asNumber()
+ {
+ return null;
+ }
+
+ public boolean isNumber()
+ {
+ return false;
+ }
+
+ public Object asObject()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ return value;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Context.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Context.java
new file mode 100644
index 000000000..f6d1ebc10
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Context.java
@@ -0,0 +1,62 @@
+/* gnu.classpath.tools.gjdoc.expr.Context
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+import java.util.Set;
+
+class Context
+{
+ private EvaluatorEnvironment evaluatorEnvironment;
+ private Set visitedFields;
+
+ Context(EvaluatorEnvironment evaluatorEnvironment, Set visitedFields)
+ {
+ this.evaluatorEnvironment = evaluatorEnvironment;
+ this.visitedFields = visitedFields;
+ }
+
+ public EvaluatorEnvironment getEvaluatorEnvironment()
+ {
+ return evaluatorEnvironment;
+ }
+
+ public Set getVisitedFields()
+ {
+ return visitedFields;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/DivisionExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/DivisionExpression.java
new file mode 100644
index 000000000..85206d4fb
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/DivisionExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.DivisionExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class DivisionExpression
+ extends BinaryComputationExpression
+{
+ public DivisionExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected double compute(double leftValue, double rightValue)
+ {
+ return leftValue / rightValue;
+ }
+
+ protected float compute(float leftValue, float rightValue)
+ {
+ return leftValue / rightValue;
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue / rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue / rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EqualExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EqualExpression.java
new file mode 100644
index 000000000..d7385fd7c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EqualExpression.java
@@ -0,0 +1,72 @@
+/* gnu.classpath.tools.gjdoc.expr.EqualExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class EqualExpression
+ extends BinaryEqualityExpression
+{
+ public EqualExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected boolean compute(double leftValue, double rightValue)
+ {
+ return leftValue == rightValue;
+ }
+
+ protected boolean compute(float leftValue, float rightValue)
+ {
+ return leftValue == rightValue;
+ }
+
+ protected boolean compute(long leftValue, long rightValue)
+ {
+ return leftValue == rightValue;
+ }
+
+ protected boolean compute(int leftValue, int rightValue)
+ {
+ return leftValue == rightValue;
+ }
+
+ protected boolean compute(boolean leftValue, boolean rightValue)
+ {
+ return leftValue == rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Evaluator.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Evaluator.java
new file mode 100644
index 000000000..d12da3519
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Evaluator.java
@@ -0,0 +1,148 @@
+/* gnu.classpath.tools.gjdoc.expr.Evaluator
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+import java.io.StringReader;
+import java.math.BigInteger;
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import java.util.Set;
+
+public class Evaluator
+{
+ /**
+ * Try to evaluate the given Java expression in the context of the
+ * given environment.
+ *
+ * @param expression the Java expression to evaluate. The
+ * expression string must not include a terminating semicolon.
+ *
+ * @param source the FieldDoc (part of) whose constant field value
+ * expression is being evaluated. Used to prevent circular
+ * references.
+ *
+ * @param environment callback hook used by the Evaluator to query
+ * the value of static fields referenced in the expression.
+ *
+ * @return a Java object representing the value of the expression,
+ * or <code>null</code> if the expression evaluates to
+ * <code>null</code>.
+ *
+ * @throws IllegalExpressionException if the expression is
+ * invalid, uses unsupported syntax constructs (e.g. method calls,
+ * array access) or references unknown static fields.
+ */
+ public static Object evaluate(String expression,
+ Set visitedFields,
+ EvaluatorEnvironment environment)
+ throws IllegalExpressionException
+ {
+ try {
+ JavaLexer lexer = new JavaLexer(new StringReader(expression));
+ JavaRecognizer recognizer = new JavaRecognizer(lexer);
+ Expression e = recognizer.expression();
+ ConstantExpression value = e.evaluate(new Context(environment, visitedFields));
+ return value.asObject();
+ }
+ catch (RecognitionException e) {
+ throw new IllegalExpressionException(e);
+ }
+ catch (TokenStreamException e) {
+ throw new IllegalExpressionException(e);
+ }
+ }
+
+ static int parseInt(String stringValue)
+ {
+ int base = 10;
+
+ if (stringValue.startsWith("0x")) {
+ base = 16;
+ stringValue = stringValue.substring(2);
+ }
+ else if (stringValue.length() > 1 && stringValue.startsWith("0")) {
+ base = 8;
+ stringValue = stringValue.substring(1);
+ }
+ while (stringValue.length() > 1 && stringValue.startsWith("0")) {
+ stringValue = stringValue.substring(1);
+ }
+
+ if (10 == base) {
+ return Integer.parseInt(stringValue);
+ }
+ else {
+ long result = Long.parseLong(stringValue, base);
+
+ if (result > Integer.MAX_VALUE) {
+ result -= 0x100000000L;
+ }
+
+ if (result > Integer.MAX_VALUE) {
+ throw new NumberFormatException(result + " > " + Integer.MAX_VALUE);
+ }
+ else if (result < Integer.MIN_VALUE) {
+ throw new NumberFormatException(result + " < " + Integer.MIN_VALUE);
+ }
+ else {
+ return (int)result;
+ }
+ }
+ }
+
+ static long parseLong(String stringValue)
+ {
+ int base = 10;
+
+ if (stringValue.startsWith("0x")) {
+ base = 16;
+ stringValue = stringValue.substring(2);
+ }
+ else if (stringValue.length() > 1 && stringValue.startsWith("0")) {
+ base = 8;
+ stringValue = stringValue.substring(1);
+ }
+ while (stringValue.length() > 1 && stringValue.startsWith("0")) {
+ stringValue = stringValue.substring(1);
+ }
+
+ BigInteger bigInt = new BigInteger(stringValue, base);
+ long result = bigInt.longValue();
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EvaluatorEnvironment.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EvaluatorEnvironment.java
new file mode 100644
index 000000000..cf4df8938
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/EvaluatorEnvironment.java
@@ -0,0 +1,46 @@
+/* gnu.classpath.tools.gjdoc.expr.EvaluatorEnvironment
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+import java.util.Set;
+
+public interface EvaluatorEnvironment
+{
+ public Object getValue(String identifier, Set visitedFields)
+ throws IllegalExpressionException, UnknownIdentifierException;
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ExclusiveOrExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ExclusiveOrExpression.java
new file mode 100644
index 000000000..eb992fc28
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ExclusiveOrExpression.java
@@ -0,0 +1,57 @@
+/* gnu.classpath.tools.gjdoc.expr.ExclusiveOrExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ExclusiveOrExpression
+ extends BinaryBitwiseExpression
+{
+ public ExclusiveOrExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue ^ rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue ^ rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Expression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Expression.java
new file mode 100644
index 000000000..ca1ccc645
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Expression.java
@@ -0,0 +1,44 @@
+/* gnu.classpath.tools.gjdoc.expr.Expression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+interface Expression
+{
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException;
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanExpression.java
new file mode 100644
index 000000000..995f7ae80
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.GreaterThanExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class GreaterThanExpression
+ extends BinaryRelationExpression
+{
+ public GreaterThanExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected boolean compute(double leftValue, double rightValue)
+ {
+ return leftValue > rightValue;
+ }
+
+ protected boolean compute(float leftValue, float rightValue)
+ {
+ return leftValue > rightValue;
+ }
+
+ protected boolean compute(long leftValue, long rightValue)
+ {
+ return leftValue > rightValue;
+ }
+
+ protected boolean compute(int leftValue, int rightValue)
+ {
+ return leftValue > rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanOrEqualExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanOrEqualExpression.java
new file mode 100644
index 000000000..4e7ca4a01
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/GreaterThanOrEqualExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.GreaterThanOrEqualExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class GreaterThanOrEqualExpression
+ extends BinaryRelationExpression
+{
+ public GreaterThanOrEqualExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected boolean compute(double leftValue, double rightValue)
+ {
+ return leftValue >= rightValue;
+ }
+
+ protected boolean compute(float leftValue, float rightValue)
+ {
+ return leftValue >= rightValue;
+ }
+
+ protected boolean compute(long leftValue, long rightValue)
+ {
+ return leftValue >= rightValue;
+ }
+
+ protected boolean compute(int leftValue, int rightValue)
+ {
+ return leftValue >= rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IdentifierExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IdentifierExpression.java
new file mode 100644
index 000000000..8d254927c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IdentifierExpression.java
@@ -0,0 +1,89 @@
+/* gnu.classpath.tools.gjdoc.expr.IdentifierExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class IdentifierExpression
+ implements Expression
+{
+ private String identifier;
+
+ public IdentifierExpression(String identifier)
+ {
+ this.identifier = identifier;
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ Object value = context.getEvaluatorEnvironment().getValue(identifier, context.getVisitedFields());
+
+ if (value instanceof Byte) {
+ return new ConstantByte(((Byte)value).byteValue());
+ }
+ else if (value instanceof Short) {
+ return new ConstantShort(((Short)value).shortValue());
+ }
+ else if (value instanceof Integer) {
+ return new ConstantInteger(((Integer)value).intValue());
+ }
+ else if (value instanceof Long) {
+ return new ConstantLong(((Long)value).longValue());
+ }
+ else if (value instanceof Float) {
+ return new ConstantFloat(((Float)value).floatValue());
+ }
+ else if (value instanceof Double) {
+ return new ConstantDouble(((Double)value).doubleValue());
+ }
+ else if (value instanceof Boolean) {
+ return new ConstantBoolean(((Boolean)value).booleanValue());
+ }
+ else if (value instanceof Character) {
+ return new ConstantChar(((Character)value).charValue());
+ }
+ else if (value instanceof String) {
+ return new ConstantString((String)value);
+ }
+ else if (null != value) {
+ throw new IllegalExpressionException("Unsupported type " + value.getClass().getName() + " for identifier " + identifier);
+ }
+ else {
+ throw new IllegalExpressionException("Cannot resolve identifier " + identifier);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IllegalExpressionException.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IllegalExpressionException.java
new file mode 100644
index 000000000..65cd5da11
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/IllegalExpressionException.java
@@ -0,0 +1,52 @@
+/* gnu.classpath.tools.gjdoc.expr.IllegalExpressionException
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+public class IllegalExpressionException
+ extends Exception
+{
+ public IllegalExpressionException(String message)
+ {
+ super(message);
+ }
+
+ public IllegalExpressionException(Throwable cause)
+ {
+ super(cause);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/InclusiveOrExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/InclusiveOrExpression.java
new file mode 100644
index 000000000..2b0250133
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/InclusiveOrExpression.java
@@ -0,0 +1,57 @@
+/* gnu.classpath.tools.gjdoc.expr.InclusiveOrExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class InclusiveOrExpression
+ extends BinaryBitwiseExpression
+{
+ public InclusiveOrExpression(Expression a, Expression b)
+ {
+ super(a, b);
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue | rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue | rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanExpression.java
new file mode 100644
index 000000000..4e784cdcc
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.LessThanExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class LessThanExpression
+ extends BinaryRelationExpression
+{
+ public LessThanExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected boolean compute(double leftValue, double rightValue)
+ {
+ return leftValue < rightValue;
+ }
+
+ protected boolean compute(float leftValue, float rightValue)
+ {
+ return leftValue < rightValue;
+ }
+
+ protected boolean compute(long leftValue, long rightValue)
+ {
+ return leftValue < rightValue;
+ }
+
+ protected boolean compute(int leftValue, int rightValue)
+ {
+ return leftValue < rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanOrEqualExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanOrEqualExpression.java
new file mode 100644
index 000000000..803ad5ee3
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LessThanOrEqualExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.LessThanOrEqualExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class LessThanOrEqualExpression
+ extends BinaryRelationExpression
+{
+ public LessThanOrEqualExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected boolean compute(double leftValue, double rightValue)
+ {
+ return leftValue <= rightValue;
+ }
+
+ protected boolean compute(float leftValue, float rightValue)
+ {
+ return leftValue <= rightValue;
+ }
+
+ protected boolean compute(long leftValue, long rightValue)
+ {
+ return leftValue <= rightValue;
+ }
+
+ protected boolean compute(int leftValue, int rightValue)
+ {
+ return leftValue <= rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalAndExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalAndExpression.java
new file mode 100644
index 000000000..3b0409155
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalAndExpression.java
@@ -0,0 +1,52 @@
+/* gnu.classpath.tools.gjdoc.expr.LogicalAndExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class LogicalAndExpression
+ extends BinaryLogicalExpression
+{
+ LogicalAndExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected boolean compute(boolean leftValue, boolean rightValue)
+ {
+ return leftValue && rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalNotExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalNotExpression.java
new file mode 100644
index 000000000..4c7bf70f7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalNotExpression.java
@@ -0,0 +1,60 @@
+/* gnu.classpath.tools.gjdoc.expr.LogicalNotExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class LogicalNotExpression
+ extends UnaryExpression
+{
+ protected LogicalNotExpression(Expression expr)
+ {
+ super(expr);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression value = expr.evaluate(context);
+
+ if (Type.BOOLEAN == value.getType()) {
+ return new ConstantBoolean(!((ConstantBoolean)value).booleanValue());
+ }
+ else {
+ throw new IllegalExpressionException("Operator ! cannot be applied to " + value.getType());
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalOrExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalOrExpression.java
new file mode 100644
index 000000000..625a6e5e8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/LogicalOrExpression.java
@@ -0,0 +1,52 @@
+/* gnu.classpath.tools.gjdoc.expr.LogicalOrExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class LogicalOrExpression
+ extends BinaryLogicalExpression
+{
+ LogicalOrExpression(Expression a, Expression b)
+ {
+ super(a, b);
+ }
+
+ protected boolean compute(boolean leftValue, boolean rightValue)
+ {
+ return leftValue || rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ModuloExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ModuloExpression.java
new file mode 100644
index 000000000..6aca379dc
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ModuloExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.ModuloExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ModuloExpression
+ extends BinaryComputationExpression
+{
+ public ModuloExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected double compute(double leftValue, double rightValue)
+ {
+ return leftValue % rightValue;
+ }
+
+ protected float compute(float leftValue, float rightValue)
+ {
+ return leftValue % rightValue;
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue % rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue % rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/MultiplicationExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/MultiplicationExpression.java
new file mode 100644
index 000000000..3d3071a50
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/MultiplicationExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.MultiplicationExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class MultiplicationExpression
+ extends BinaryComputationExpression
+{
+ public MultiplicationExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected double compute(double leftValue, double rightValue)
+ {
+ return leftValue * rightValue;
+ }
+
+ protected float compute(float leftValue, float rightValue)
+ {
+ return leftValue * rightValue;
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue * rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue * rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NegateExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NegateExpression.java
new file mode 100644
index 000000000..5b66fecd2
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NegateExpression.java
@@ -0,0 +1,66 @@
+/* gnu.classpath.tools.gjdoc.expr.NegateExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class NegateExpression
+ extends UnaryExpression
+{
+ protected NegateExpression(Expression expr)
+ {
+ super(expr);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression value = expr.evaluate(context);
+
+ if (Type.LONG == value.getType()) {
+ return new ConstantLong(-value.asNumber().longValue());
+ }
+ else if (Type.DOUBLE == value.getType()) {
+ return new ConstantDouble(-value.asNumber().doubleValue());
+ }
+ else if (Type.FLOAT == value.getType()) {
+ return new ConstantDouble(-value.asNumber().floatValue());
+ }
+ else {
+ return new ConstantInteger(-value.asNumber().intValue());
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotEqualExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotEqualExpression.java
new file mode 100644
index 000000000..eb49bc087
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotEqualExpression.java
@@ -0,0 +1,72 @@
+/* gnu.classpath.tools.gjdoc.expr.NotEqualExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class NotEqualExpression
+ extends BinaryEqualityExpression
+{
+ public NotEqualExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected boolean compute(double leftValue, double rightValue)
+ {
+ return leftValue != rightValue;
+ }
+
+ protected boolean compute(float leftValue, float rightValue)
+ {
+ return leftValue != rightValue;
+ }
+
+ protected boolean compute(long leftValue, long rightValue)
+ {
+ return leftValue != rightValue;
+ }
+
+ protected boolean compute(int leftValue, int rightValue)
+ {
+ return leftValue != rightValue;
+ }
+
+ protected boolean compute(boolean leftValue, boolean rightValue)
+ {
+ return leftValue != rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotExpression.java
new file mode 100644
index 000000000..7359a055a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/NotExpression.java
@@ -0,0 +1,60 @@
+/* gnu.classpath.tools.gjdoc.expr.NotExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class NotExpression
+ extends UnaryExpression
+{
+ protected NotExpression(Expression expr)
+ {
+ super(expr);
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression value = expr.evaluate(context);
+
+ if (Type.LONG == value.getType()) {
+ return new ConstantLong(~value.asNumber().longValue());
+ }
+ else {
+ return new ConstantInteger(~value.asNumber().intValue());
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftLeftExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftLeftExpression.java
new file mode 100644
index 000000000..ad72efbfb
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftLeftExpression.java
@@ -0,0 +1,57 @@
+/* gnu.classpath.tools.gjdoc.expr.ShiftLeftExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ShiftLeftExpression
+ extends BinaryShiftExpression
+{
+ public ShiftLeftExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected long compute(long leftValue, int rightValue)
+ {
+ return leftValue << rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue << rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftRightExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftRightExpression.java
new file mode 100644
index 000000000..f9d7820bb
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/ShiftRightExpression.java
@@ -0,0 +1,57 @@
+/* gnu.classpath.tools.gjdoc.expr.ShiftRightExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class ShiftRightExpression
+ extends BinaryShiftExpression
+{
+ public ShiftRightExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected long compute(long leftValue, int rightValue)
+ {
+ return leftValue >> rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue >> rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/SubtractionExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/SubtractionExpression.java
new file mode 100644
index 000000000..dc0101ffc
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/SubtractionExpression.java
@@ -0,0 +1,67 @@
+/* gnu.classpath.tools.gjdoc.expr.SubtractionExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class SubtractionExpression
+ extends BinaryComputationExpression
+{
+ public SubtractionExpression(Expression left, Expression right)
+ {
+ super(left, right);
+ }
+
+ protected double compute(double leftValue, double rightValue)
+ {
+ return leftValue - rightValue;
+ }
+
+ protected float compute(float leftValue, float rightValue)
+ {
+ return leftValue - rightValue;
+ }
+
+ protected long compute(long leftValue, long rightValue)
+ {
+ return leftValue - rightValue;
+ }
+
+ protected int compute(int leftValue, int rightValue)
+ {
+ return leftValue - rightValue;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Type.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Type.java
new file mode 100644
index 000000000..92382c41a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/Type.java
@@ -0,0 +1,60 @@
+/* gnu.classpath.tools.gjdoc.expr.Type
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class Type
+{
+ public static final Type LONG = new Type(Long.TYPE);
+ public static final Type INTEGER = new Type(Integer.TYPE);
+ public static final Type BOOLEAN = new Type(Boolean.TYPE);
+ public static final Type DOUBLE = new Type(Double.TYPE);
+ public static final Type FLOAT = new Type(Float.TYPE);
+ public static final Type CHAR = new Type(Character.TYPE);
+ public static final Type BYTE = new Type(Byte.TYPE);
+ public static final Type SHORT = new Type(Short.TYPE);
+ public static final Type VOID = new Type(Void.TYPE);
+ public static final Type STRING = new Type(String.class);
+ public static final Type NULL = new Type(null);
+
+ private Class clazz;
+
+ private Type(Class clazz)
+ {
+ this.clazz = clazz;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/TypeCastExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/TypeCastExpression.java
new file mode 100644
index 000000000..c434ae870
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/TypeCastExpression.java
@@ -0,0 +1,87 @@
+/* gnu.classpath.tools.gjdoc.expr.TypeCastExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+class TypeCastExpression
+ extends UnaryExpression
+{
+ private Type type;
+
+ public TypeCastExpression(Type type, Expression expr)
+ {
+ super(expr);
+ this.type = type;
+ }
+
+ public ConstantExpression evaluate(Context context)
+ throws IllegalExpressionException
+ {
+ ConstantExpression value = expr.evaluate(context);
+
+ if (Type.BYTE == type) {
+ return new ConstantByte(value.asNumber().byteValue());
+ }
+ else if (Type.SHORT == type) {
+ return new ConstantShort(value.asNumber().shortValue());
+ }
+ else if (Type.INTEGER == type) {
+ return new ConstantInteger(value.asNumber().intValue());
+ }
+ else if (Type.LONG == type) {
+ return new ConstantLong(value.asNumber().longValue());
+ }
+ else if (Type.CHAR == type) {
+ return new ConstantChar((char)value.asNumber().intValue());
+ }
+ else if (Type.FLOAT == type) {
+ return new ConstantFloat((float)value.asNumber().intValue());
+ }
+ else if (Type.DOUBLE == type) {
+ return new ConstantDouble((float)value.asNumber().intValue());
+ }
+ else if (Type.BOOLEAN == type && Type.BOOLEAN == value.getType()) {
+ return value;
+ }
+ else if (Type.STRING == type && Type.STRING == value.getType()) {
+ return value;
+ }
+ else {
+ throw new IllegalExpressionException("Cannot cast " + value.getType() + " to " + type);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnaryExpression.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnaryExpression.java
new file mode 100644
index 000000000..33befcb84
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnaryExpression.java
@@ -0,0 +1,49 @@
+/* gnu.classpath.tools.gjdoc.expr.UnaryExpression
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+abstract class UnaryExpression
+ implements Expression
+{
+ protected Expression expr;
+
+ protected UnaryExpression(Expression expr)
+ {
+ this.expr = expr;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnknownIdentifierException.java b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnknownIdentifierException.java
new file mode 100644
index 000000000..894a71716
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/UnknownIdentifierException.java
@@ -0,0 +1,47 @@
+/* gnu.classpath.tools.gjdoc.expr.UnknownIdentifierException
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.gjdoc.expr;
+
+public class UnknownIdentifierException
+ extends IllegalExpressionException
+{
+ public UnknownIdentifierException(String identifier)
+ {
+ super(identifier);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/java-expression.g b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/java-expression.g
new file mode 100644
index 000000000..4a21a8618
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/gjdoc/expr/java-expression.g
@@ -0,0 +1,471 @@
+/*
+ * This grammar is derived from the Java 1.3 Recognizer
+ * (http://www.antlr.org/grammar/java/java.g) by Mitchell, Parr, Lilley,
+ * Stanchfield, Mohnen, Williams, Jacobs, Messick and Pybus, Version
+ * 1.21.
+ *
+ * This grammar recognizes simple Java expressions. The following
+ * language elements are NOT supported:
+ *
+ * - type casts to non-primitive types
+ * - method calls
+ * - constructor calls
+ * - array access
+ * - comma expressions
+ * - increment and decrement operators (both prefix/postfix)
+ * - expressions involving constant classes (Abc.class)
+ */
+
+header {
+ package gnu.classpath.tools.gjdoc.expr;
+}
+
+class JavaRecognizer extends Parser;
+options {
+ k = 2; // two token lookahead
+ exportVocab=Java; // Call its vocabulary "Java"
+ codeGenMakeSwitchThreshold = 2; // Some optimizations
+ codeGenBitsetTestThreshold = 3;
+ defaultErrorHandler = false; // Don't generate parser error handlers
+ buildAST = true;
+}
+
+tokens {
+ BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
+ INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+ PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+ PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+ POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
+ IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+ FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+ STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL;
+}
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec[boolean addImagNode] returns [Type t = null]
+ : t=builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ {
+ if ( addImagNode ) {
+ #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
+ }
+ }
+ ;
+
+// A type name. which is either a (possibly qualified) class name or
+// a primitive (builtin) type
+type returns [Type t]
+ : t=builtInType
+ ;
+
+// The primitive types.
+builtInType returns [Type t = null]
+ : "void" {t=Type.VOID;}
+ | "boolean" {t=Type.BOOLEAN;}
+ | "byte" {t=Type.BYTE;}
+ | "char" {t=Type.CHAR;}
+ | "short" {t=Type.SHORT;}
+ | "int" {t=Type.INTEGER;}
+ | "float"{t=Type.FLOAT;}
+ | "long" {t=Type.LONG;}
+ | "double" {t=Type.DOUBLE;}
+ | "String" {t=Type.STRING;}
+ ;
+
+// A (possibly-qualified) java identifier. We start with the first IDENT
+// and expand its name by adding dots and following IDENTS
+identifier returns [String s = null;]
+ : i:IDENT {s=i.getText();} ( DOT^ i2:IDENT {s+="."+i2.getText();} )*
+ ;
+
+expression returns [Expression e = null]
+ : e=conditionalExpression EOF!
+ ;
+
+// conditional test (level 12)
+conditionalExpression returns [Expression e = null] { Expression a,b,c; }
+ : e=logicalOrExpression
+ ( QUESTION^ b=conditionalExpression COLON! c=conditionalExpression {e=new ConditionalExpression(e,b,c);} )?
+ ;
+
+
+// logical or (||) (level 11)
+logicalOrExpression returns [Expression e = null] { Expression a,b; }
+ : e=logicalAndExpression (LOR^ b=logicalAndExpression {e=new LogicalOrExpression(e,b);})*
+ ;
+
+
+// logical and (&&) (level 10)
+logicalAndExpression returns [Expression e = null] { Expression a,b; }
+ : e=inclusiveOrExpression (LAND^ b=inclusiveOrExpression {e=new LogicalAndExpression(e,b);})*
+ ;
+
+
+// bitwise or non-short-circuiting or (|) (level 9)
+inclusiveOrExpression returns [Expression e = null] { Expression a,b; }
+ : e=exclusiveOrExpression (BOR^ b=exclusiveOrExpression {e=new InclusiveOrExpression(e,b);})*
+ ;
+
+
+// exclusive or (^) (level 8)
+exclusiveOrExpression returns [Expression e = null] { Expression a,b; }
+ : e=andExpression (BXOR^ b=andExpression {e=new ExclusiveOrExpression(e,b);})*
+ ;
+
+
+// bitwise or non-short-circuiting and (&) (level 7)
+andExpression returns [Expression e = null] { Expression a,b; }
+ : e=equalityExpression (BAND^ b=equalityExpression {e=new AndExpression(e,b);})*
+ ;
+
+
+// equality/inequality (==/!=) (level 6)
+equalityExpression returns [Expression e = null] { Expression a,b; }
+ : e=relationalExpression ((NOT_EQUAL^ a=relationalExpression {e=new NotEqualExpression(e,a);} | EQUAL^ a=relationalExpression {e=new EqualExpression(e,a);}))*
+ ;
+
+
+// boolean relational expressions (level 5)
+relationalExpression returns [Expression e = null] { Expression a,b; }
+ : e=shiftExpression
+ ( ( ( LT^ a=shiftExpression {e=new LessThanExpression(e,a);}
+ | GT^ a=shiftExpression {e=new GreaterThanExpression(e,a);}
+ | LE^ a=shiftExpression {e=new LessThanOrEqualExpression(e,a);}
+ | GE^ a=shiftExpression {e=new GreaterThanOrEqualExpression(e,a);}
+ )
+
+ )*
+ )
+ ;
+
+
+// bit shift expressions (level 4)
+shiftExpression returns [Expression e = null] { Expression a,b; }
+ : e=additiveExpression ((SL^ a=additiveExpression {e=new ShiftLeftExpression(e,a);} | SR^ a=additiveExpression {e=new ShiftRightExpression(e,a);} | BSR^ a=additiveExpression {e=new BitShiftRightExpression(e,a);}))*
+ ;
+
+
+// binary addition/subtraction (level 3)
+additiveExpression returns [Expression e = null] { Expression a,b; }
+ : e=multiplicativeExpression ((PLUS^ a=multiplicativeExpression {e=new AdditionExpression(e,a);} | MINUS^ a=multiplicativeExpression {e=new SubtractionExpression(e,a);}))*
+ ;
+
+
+// multiplication/division/modulo (level 2)
+multiplicativeExpression returns [Expression e = null] { Expression a,b; }
+ : e=unaryExpression ((STAR^ a=unaryExpression {e=new MultiplicationExpression(e,a);} | DIV^ a=unaryExpression {e=new DivisionExpression(e,a);} | MOD^ a=unaryExpression {e=new ModuloExpression(e,a);} ))*
+ ;
+
+
+unaryExpression returns [Expression e = null] { Expression a,b; }
+ : MINUS^ {#MINUS.setType(UNARY_MINUS);} a=unaryExpression {e=new NegateExpression(a);}
+ | PLUS^ {#PLUS.setType(UNARY_PLUS);} e=unaryExpression
+ | e=unaryExpressionNotPlusMinus
+ ;
+
+unaryExpressionNotPlusMinus returns [Expression e = null] { Expression a; Type t; }
+ : BNOT^ a=unaryExpression {e=new NotExpression(a);}
+ | LNOT^ a=unaryExpression {e=new LogicalNotExpression(a);}
+
+ // use predicate to skip cases like: (int.class)
+ | (LPAREN builtInTypeSpec[true] RPAREN) =>
+ lpb:LPAREN^ {#lpb.setType(TYPECAST);} t=builtInTypeSpec[true] RPAREN!
+ a=unaryExpression {e=new TypeCastExpression(t,a);}
+
+ | e=primaryExpression
+ ;
+
+// the basic element of an expression
+primaryExpression returns [Expression e = null; String i = null;]
+ : e=constant
+ | i=identifier {e=new IdentifierExpression(i);}
+ | "true" { e=new ConstantBoolean(true); }
+ | "false" { e=new ConstantBoolean(false); }
+ | "null" { e=new ConstantNull(); }
+ | LPAREN! e=conditionalExpression RPAREN!
+ ;
+
+/** Match a, a.b.c refs
+ */
+identPrimary returns [Expression e = null]
+ : IDENT
+ (
+ options {
+ // .ident could match here or in postfixExpression.
+ // We do want to match here. Turn off warning.
+ greedy=true;
+ }
+ : DOT^ IDENT
+ )*
+ ;
+
+constant returns [Expression e = null]
+ : l1:NUM_INT {e=new ConstantInteger(l1.getText());}
+ | l2:CHAR_LITERAL {e=new ConstantChar(l2.getText());}
+ | l3:STRING_LITERAL {e=new ConstantString(l3.getText().substring(1, l3.getText().length()-1)); }
+ | l4:NUM_FLOAT {e=new ConstantFloat(l4.getText());}
+ | l5:NUM_LONG {e=new ConstantLong(l5.getText());}
+ | l6:NUM_DOUBLE {e=new ConstantDouble(l6.getText());}
+ ;
+
+
+//----------------------------------------------------------------------------
+// The Java scanner
+//----------------------------------------------------------------------------
+class JavaLexer extends Lexer;
+
+options {
+ exportVocab=Java; // call the vocabulary "Java"
+ testLiterals=false; // don't automatically test for literals
+ k=4; // four characters of lookahead
+ charVocabulary='\u0003'..'\uFFFF';
+ // without inlining some bitset tests, couldn't do unicode;
+ // I need to make ANTLR generate smaller bitsets; see
+ // bottom of JavaLexer.java
+ codeGenBitsetTestThreshold=20;
+}
+
+
+
+// OPERATORS
+QUESTION : '?' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+LBRACK : '[' ;
+RBRACK : ']' ;
+LCURLY : '{' ;
+RCURLY : '}' ;
+COLON : ':' ;
+COMMA : ',' ;
+//DOT : '.' ;
+ASSIGN : '=' ;
+EQUAL : "==" ;
+LNOT : '!' ;
+BNOT : '~' ;
+NOT_EQUAL : "!=" ;
+DIV : '/' ;
+DIV_ASSIGN : "/=" ;
+PLUS : '+' ;
+PLUS_ASSIGN : "+=" ;
+INC : "++" ;
+MINUS : '-' ;
+MINUS_ASSIGN : "-=" ;
+DEC : "--" ;
+STAR : '*' ;
+STAR_ASSIGN : "*=" ;
+MOD : '%' ;
+MOD_ASSIGN : "%=" ;
+SR : ">>" ;
+SR_ASSIGN : ">>=" ;
+BSR : ">>>" ;
+BSR_ASSIGN : ">>>=" ;
+GE : ">=" ;
+GT : ">" ;
+SL : "<<" ;
+SL_ASSIGN : "<<=" ;
+LE : "<=" ;
+LT : '<' ;
+BXOR : '^' ;
+BXOR_ASSIGN : "^=" ;
+BOR : '|' ;
+BOR_ASSIGN : "|=" ;
+LOR : "||" ;
+BAND : '&' ;
+BAND_ASSIGN : "&=" ;
+LAND : "&&" ;
+SEMI : ';' ;
+
+
+// Whitespace -- ignored
+WS : ( ' '
+ | '\t'
+ | '\f'
+ // handle newlines
+ | ( options {generateAmbigWarnings=false;}
+ : "\r\n" // Evil DOS
+ | '\r' // Macintosh
+ | '\n' // Unix (the right way)
+ )
+ { newline(); }
+ )+
+ { _ttype = Token.SKIP; }
+ ;
+
+// Single-line comments
+SL_COMMIT
+ : "//"
+ (~('\n'|'\r'))* ('\n'|'\r'('\n')?)
+ {$setType(Token.SKIP); newline();}
+ ;
+
+// multiple-line comments
+ML_COMMENT
+ : "/*"
+ ( /* '\r' '\n' can be matched in one alternative or by matching
+ '\r' in one iteration and '\n' in another. I am trying to
+ handle any flavor of newline that comes in, but the language
+ that allows both "\r\n" and "\r" and "\n" to all be valid
+ newline is ambiguous. Consequently, the resulting grammar
+ must be ambiguous. I'm shutting this warning off.
+ */
+ options {
+ generateAmbigWarnings=false;
+ }
+ :
+ { LA(2)!='/' }? '*'
+ | '\r' '\n' {newline();}
+ | '\r' {newline();}
+ | '\n' {newline();}
+ | ~('*'|'\n'|'\r')
+ )*
+ "*/"
+ {$setType(Token.SKIP);}
+ ;
+
+
+// character literals
+CHAR_LITERAL
+ : '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
+ ;
+
+// string literals
+STRING_LITERAL
+ : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
+ ;
+
+
+// escape sequence -- note that this is protected; it can only be called
+// from another lexer rule -- it will not ever directly return a token to
+// the parser
+// There are various ambiguities hushed in this rule. The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched. ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+ : '\\'
+ ( 'n'
+ | 'r'
+ | 't'
+ | 'b'
+ | 'f'
+ | '"'
+ | '\''
+ | '\\'
+ | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+ | '0'..'3'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )?
+ | '4'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )
+ ;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+ : ('0'..'9'|'A'..'F'|'a'..'f')
+ ;
+
+
+// a dummy rule to force vocabulary to be all characters (except special
+// ones that ANTLR uses internally (0 to 2)
+protected
+VOCAB
+ : '\3'..'\377'
+ ;
+
+
+// an identifier. Note that testLiterals is set to true! This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+ options {testLiterals=true;}
+ : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+ ;
+
+
+// a numeric literal
+NUM_INT
+ {boolean isDecimal=false; Token t=null;}
+ : '.' {_ttype = DOT;}
+ ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+ {
+ if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ )?
+
+ | ( '0' {isDecimal = true;} // special case for just '0'
+ ( ('x'|'X')
+ ( // hex
+ // the 'e'|'E' and float suffix stuff look
+ // like hex digits, hence the (...)+ doesn't
+ // know when to stop: ambig. ANTLR resolves
+ // it correctly by matching immediately. It
+ // is therefor ok to hush warning.
+ options {
+ warnWhenFollowAmbig=false;
+ }
+ : HEX_DIGIT
+ )+
+
+ | //float or double with leading zero
+ (('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
+
+ | ('0'..'7')+ // octal
+ )?
+ | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
+ )
+ ( ('l'|'L') { _ttype = NUM_LONG; }
+
+ // only check to see if it's a float if looks like decimal so far
+ | {isDecimal}?
+ ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+ | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+ | f4:FLOAT_SUFFIX {t=f4;}
+ )
+ {
+ if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ )?
+ ;
+
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+ : ('e'|'E') ('+'|'-')? ('0'..'9')+
+ ;
+
+
+protected
+FLOAT_SUFFIX
+ : 'f'|'F'|'d'|'D'
+ ;
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Action.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Action.java
new file mode 100644
index 000000000..6363157ae
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Action.java
@@ -0,0 +1,51 @@
+/* Action.java - an action taken by the jar driver
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import java.io.IOException;
+
+public abstract class Action
+{
+ protected Action()
+ {
+ }
+
+ public abstract void run(Main parameters)
+ throws IOException;
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Creator.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Creator.java
new file mode 100644
index 000000000..be8d2a16f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Creator.java
@@ -0,0 +1,251 @@
+/* Creator.java - create a new jar file
+ Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+
+public class Creator
+ extends Action
+{
+ JarOutputStream outputStream;
+ HashSet<String> writtenItems = new HashSet<String>();
+ // The manifest to use, or null if we don't want a manifest.
+ Manifest manifest;
+
+ private long copyFile(CRC32 crc, InputStream is, OutputStream output)
+ throws IOException
+ {
+ byte[] buffer = new byte[1024];
+ long size = 0;
+ while (true)
+ {
+ int len = is.read(buffer);
+ if (len == - 1)
+ break;
+ size += len;
+ output.write(buffer, 0, len);
+ crc.update(buffer, 0, len);
+ }
+ output.close();
+ return size;
+ }
+
+ protected void writeFile(boolean isDirectory, InputStream inputFile,
+ String filename, boolean verbose)
+ throws IOException
+ {
+ if (writtenItems.contains(filename))
+ {
+ if (verbose)
+ {
+ String msg = MessageFormat.format(Messages.getString("Creator.Ignoring"), //$NON-NLS-1$
+ new Object[] { filename });
+ System.err.println(msg);
+ }
+ return;
+ }
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ CRC32 crc = new CRC32();
+ long size;
+ if (isDirectory)
+ {
+ size = 0;
+ }
+ else
+ {
+ size = copyFile(crc, inputFile, out);
+ }
+
+ ZipEntry entry = new ZipEntry(filename);
+ entry.setCrc(crc.getValue());
+ entry.setSize(size);
+
+ outputStream.putNextEntry(entry);
+ out.writeTo(outputStream);
+ outputStream.closeEntry();
+ writtenItems.add(filename);
+
+ if (verbose)
+ {
+ long csize = entry.getCompressedSize();
+ long perc;
+ if (size == 0)
+ perc = 0;
+ else
+ perc = 100 - (100 * csize) / size;
+ String msg = MessageFormat.format(Messages.getString("Creator.Adding"), //$NON-NLS-1$
+ new Object[]
+ {
+ filename,
+ Long.valueOf(size),
+ Long.valueOf(entry.getSize()),
+ Long.valueOf(perc)
+ });
+ System.err.println(msg);
+ }
+ }
+
+ protected void writeFile(File file, String filename, boolean verbose)
+ throws IOException
+ {
+ boolean isDirectory = file.isDirectory();
+ if (isDirectory)
+ {
+ if (filename.charAt(filename.length() - 1) != '/')
+ filename += '/';
+ writeFile(isDirectory, null, filename, verbose);
+ }
+ else
+ {
+ InputStream inputStream = new FileInputStream(file);
+ writeFile(isDirectory, inputStream, filename, verbose);
+ inputStream.close();
+ }
+ }
+
+ private void addEntries(ArrayList<Entry> result, Entry entry)
+ {
+ if (entry.file.isDirectory())
+ {
+ String name = entry.name;
+ if (name.charAt(name.length() - 1) != '/')
+ {
+ name += '/';
+ entry = new Entry(entry.file, name);
+ }
+ result.add(entry);
+ String[] files = entry.file.list();
+ for (int i = 0; i < files.length; ++i)
+ addEntries(result, new Entry(new File(entry.file, files[i]),
+ entry.name + files[i]));
+ }
+ else
+ result.add(entry);
+ }
+
+ private ArrayList<Entry> getAllEntries(Main parameters)
+ {
+ ArrayList<Entry> allEntries = new ArrayList<Entry>();
+ for (Entry entry : parameters.entries)
+ addEntries(allEntries, entry);
+ return allEntries;
+ }
+
+ private void writeCommandLineEntries(Main parameters)
+ throws IOException
+ {
+ // We've already written the manifest, make sure to mark it.
+ writtenItems.add("META-INF/"); //$NON-NLS-1$
+ writtenItems.add(JarFile.MANIFEST_NAME);
+
+ ArrayList<Entry> allEntries = getAllEntries(parameters);
+ for (Entry entry : allEntries)
+ writeFile(entry.file, entry.name, parameters.verbose);
+ }
+
+ protected Manifest createManifest(Main parameters)
+ throws IOException
+ {
+ if (! parameters.wantManifest)
+ return null;
+ if (parameters.manifestFile != null)
+ {
+ // User specified a manifest file.
+ InputStream contents = new FileInputStream(parameters.manifestFile);
+ return new Manifest(contents);
+ }
+ return new Manifest();
+ }
+
+ protected void writeCommandLineEntries(Main parameters, OutputStream os)
+ throws IOException
+ {
+ manifest = createManifest(parameters);
+ /* If no version is specified, provide the same manifest version default
+ * as Sun's jar tool */
+ if (parameters.wantManifest)
+ {
+ Attributes attr = manifest.getMainAttributes();
+ if (attr.getValue(Attributes.Name.MANIFEST_VERSION) == null)
+ attr.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
+ attr.putValue("Created-By", System.getProperty("java.version") +
+ " (" + System.getProperty("java.vendor") + ")");
+ }
+ outputStream = new JarOutputStream(os, manifest);
+ // FIXME: this sets the method too late for the manifest file.
+ outputStream.setMethod(parameters.storageMode);
+ writeCommandLineEntries(parameters);
+ }
+
+ protected void close() throws IOException
+ {
+ outputStream.finish();
+ outputStream.close();
+ }
+
+ public void run(Main parameters) throws IOException
+ {
+ if (parameters.archiveFile == null || parameters.archiveFile.equals("-")) //$NON-NLS-1$
+ writeCommandLineEntries(parameters, System.out);
+ else
+ {
+ OutputStream os
+ = new BufferedOutputStream(new FileOutputStream(parameters.archiveFile));
+ writeCommandLineEntries(parameters, os);
+ }
+ close();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Entry.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Entry.java
new file mode 100644
index 000000000..b9108798a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Entry.java
@@ -0,0 +1,70 @@
+/* Entry.java - represent a single file to write to a jar
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import java.io.File;
+
+public class Entry
+{
+ public File file;
+
+ public String name;
+
+ public Entry(File file, String name)
+ {
+ this.file = file;
+
+ /* Removes any './' prefixes automatically. Those caused trouble
+ * in (boot) classpath use-cases. See #32516.
+ */
+ int start = 0;
+ while (name.length() > start + 2
+ && name.codePointAt(start) == '.'
+ && name.codePointAt(start + 1) == File.separatorChar)
+ start += 2;
+
+ this.name = name.substring(start);
+ }
+
+ public Entry(File file)
+ {
+ this(file, file.toString());
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Extractor.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Extractor.java
new file mode 100644
index 000000000..203ff0566
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Extractor.java
@@ -0,0 +1,127 @@
+/* Extractor.java - action to extract from a jar file
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+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.text.MessageFormat;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class Extractor
+ extends Action
+{
+ // This is a set of all the items specified on the command line.
+ private WorkSet allItems;
+
+ private void copyFile(InputStream input, File output) throws IOException
+ {
+ FileOutputStream os = new FileOutputStream(output);
+ byte[] buffer = new byte[1024];
+ while (true)
+ {
+ int len = input.read(buffer);
+ if (len == - 1)
+ break;
+ os.write(buffer, 0, len);
+ }
+ os.close();
+ }
+
+ public void run(Main parameters) throws IOException
+ {
+ // Figure out what we want to extract.
+ allItems = new WorkSet(parameters.entries);
+ // Open the input file.
+ ZipInputStream zis;
+ File zfile = parameters.archiveFile;
+ if (zfile == null || "-".equals(zfile.getName())) //$NON-NLS-1$
+ zis = new ZipInputStream(System.in);
+ else
+ {
+ InputStream ins = new BufferedInputStream(new FileInputStream(zfile));
+ zis = new ZipInputStream(ins);
+ }
+ // Extract stuff.
+ while (true)
+ {
+ ZipEntry entry = zis.getNextEntry();
+ if (entry == null)
+ break;
+ if (! allItems.contains(entry.getName()))
+ continue;
+ File file = new File(entry.getName());
+ if (entry.isDirectory())
+ {
+ if (file.mkdirs())
+ {
+ if (parameters.verbose)
+ {
+ String msg
+ = MessageFormat.format(Messages.getString("Extractor.Created"), //$NON-NLS-1$
+ new Object[] { file });
+ System.err.println(msg);
+ }
+ }
+ continue;
+ }
+
+ File parent = file.getParentFile();
+ if (parent != null)
+ parent.mkdirs();
+
+ copyFile(zis, file);
+
+ if (parameters.verbose)
+ {
+ String fmt;
+ if (entry.getMethod() == ZipEntry.STORED)
+ fmt = Messages.getString("Extractor.Extracted"); //$NON-NLS-1$
+ else
+ fmt = Messages.getString("Extractor.Inflated"); //$NON-NLS-1$
+ String msg = MessageFormat.format(fmt, new Object[] { file });
+ System.err.println(msg);
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Indexer.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Indexer.java
new file mode 100644
index 000000000..ae79b26e9
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Indexer.java
@@ -0,0 +1,142 @@
+/* Indexer.java -- add index.list file to jar
+ Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import gnu.java.net.IndexListParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.MessageFormat;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+public class Indexer
+ extends Updater
+{
+ private void indexJarFile(StringBuilder result, File fileName,
+ boolean verbose)
+ throws IOException
+ {
+ if (verbose)
+ {
+ String msg = MessageFormat.format(Messages.getString("Indexer.Indexing"), //$NON-NLS-1$
+ new Object[] { fileName });
+ System.err.println(msg);
+ }
+ JarFile jf = new JarFile(fileName);
+
+ // Index the files in this jar.
+ // The results look a little better if we keep them
+ // in insertion order.
+ LinkedHashSet<String> entries = new LinkedHashSet<String>();
+ Enumeration e = jf.entries();
+ while (e.hasMoreElements())
+ {
+ JarEntry entry = (JarEntry) e.nextElement();
+ String name = entry.getName();
+ if (name.startsWith("META-INF/")) //$NON-NLS-1$
+ continue;
+ int index = name.lastIndexOf('/');
+ if (index != -1)
+ name = name.substring(0, index);
+ entries.add(name);
+ }
+ if (! entries.isEmpty())
+ {
+ result.append(fileName);
+ // Any line ending will do.
+ result.append('\n');
+ for (String s : entries)
+ {
+ result.append(s);
+ result.append('\n');
+ }
+ // Paragraph break.
+ result.append('\n');
+ }
+
+ // Now read pointed-to jars.
+ Manifest m = jf.getManifest();
+ if (m != null)
+ {
+ File parent = fileName.getParentFile();
+ Attributes attrs = m.getMainAttributes();
+ String jars = attrs.getValue(Attributes.Name.CLASS_PATH);
+ if (jars != null)
+ {
+ StringTokenizer st = new StringTokenizer(jars, " "); //$NON-NLS-1$
+ while (st.hasMoreTokens())
+ {
+ String name = st.nextToken();
+ indexJarFile(result, new File(parent, name), verbose);
+ }
+ }
+ }
+
+ jf.close();
+ }
+
+ protected void writeCommandLineEntries(Main parameters, OutputStream os)
+ throws IOException
+ {
+ // This is a pretty lame design. We know the super call will
+ // only have side effects and won't actually write anything important.
+ super.writeCommandLineEntries(parameters, os);
+
+ // Now compute our index file and write it.
+ StringBuilder contents = new StringBuilder();
+ indexJarFile(contents, parameters.archiveFile, parameters.verbose);
+ if (contents.length() != 0)
+ {
+ // Insert in reverse order to avoid computing anything.
+ contents.insert(0, "1.0\n\n"); //$NON-NLS-1$
+ contents.insert(0, IndexListParser.JAR_INDEX_VERSION_KEY);
+ ByteArrayInputStream in
+ = new ByteArrayInputStream(contents.toString().getBytes());
+ writeFile(false, in, IndexListParser.JAR_INDEX_FILE, parameters.verbose);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Lister.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Lister.java
new file mode 100644
index 000000000..98275f789
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Lister.java
@@ -0,0 +1,112 @@
+/* Lister.java - action to list contents of a jar file
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class Lister
+ extends Action
+{
+ private WorkSet allItems;
+
+ private long readUntilEnd(InputStream is) throws IOException
+ {
+ byte[] buffer = new byte[5 * 1024];
+ long result = 0;
+ while (true)
+ {
+ int r = is.read(buffer);
+ if (r == -1)
+ break;
+ result += r;
+ }
+ return result;
+ }
+
+ private void listJar(ZipInputStream zis, boolean verbose) throws IOException
+ {
+ MessageFormat format = null;
+ if (verbose)
+ format = new MessageFormat(" {0,date,E M dd HH:mm:ss z yyyy} {1}");
+ while (true)
+ {
+ ZipEntry entry = zis.getNextEntry();
+ if (entry == null)
+ break;
+ if (! allItems.contains(entry.getName()))
+ continue;
+ if (verbose)
+ {
+ // Read the stream; entry.getSize() is unreliable.
+ // (Also, we're just going to read it anyway.)
+ long size = readUntilEnd(zis);
+ // No easy way to right-justify the size using
+ // MessageFormat -- how odd.
+ String s = " " + size;
+ int index = Math.min(s.length() - 5, 5);
+ System.out.print(s.substring(index));
+ Object[] values = new Object[] { new Date(entry.getTime()),
+ entry.getName() };
+ System.out.println(format.format(values));
+ }
+ else
+ System.out.println(entry.getName());
+ }
+ }
+
+ public void run(Main parameters) throws IOException
+ {
+ allItems = new WorkSet(parameters.entries);
+ File file = parameters.archiveFile;
+ ZipInputStream zis;
+ if (file == null || "-".equals(file.getName()))
+ zis = new ZipInputStream(System.in);
+ else
+ zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
+ listJar(zis, parameters.verbose);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Main.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Main.java
new file mode 100644
index 000000000..34ef928fe
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Main.java
@@ -0,0 +1,293 @@
+/* Main.java - jar program main()
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.zip.ZipOutputStream;
+
+public class Main
+{
+ /** The mode of operation. This is the class representing
+ * the action; we make a new instance before using it. It
+ * must be a subclass of Action. 'null' means the mode
+ * has not yet been set. */
+ Class operationMode;
+
+ /** The archive file name. */
+ File archiveFile;
+
+ /** The zip storage mode. */
+ int storageMode = ZipOutputStream.DEFLATED;
+
+ /** True if we should read file names from stdin. */
+ boolean readNamesFromStdin = false;
+
+ /** True for verbose mode. */
+ boolean verbose = false;
+
+ /** True if we want a manifest file. */
+ boolean wantManifest = true;
+
+ /** Name of manifest file to use. */
+ File manifestFile;
+
+ /** A list of Entry objects, each describing a file to write. */
+ ArrayList<Entry> entries = new ArrayList<Entry>();
+
+ /** Used only while parsing, holds the first argument for -C. */
+ String changedDirectory;
+
+ void setArchiveFile(String filename) throws OptionException
+ {
+ if (archiveFile != null)
+ {
+ String fmt = MessageFormat.format(Messages.getString("Main.ArchiveAlreadySet"), //$NON-NLS-1$
+ new Object[] { archiveFile });
+ throw new OptionException(fmt);
+ }
+ archiveFile = new File(filename);
+ }
+
+ class HandleFile
+ extends FileArgumentCallback
+ {
+ public void notifyFile(String fileArgument)
+ {
+ Entry entry;
+ if (changedDirectory != null)
+ {
+ entry = new Entry(new File(changedDirectory, fileArgument),
+ fileArgument);
+ changedDirectory = null;
+ }
+ else
+ entry = new Entry(new File(fileArgument));
+ entries.add(entry);
+ }
+ }
+
+ // An option that knows how to set the operation mode.
+ private class ModeOption
+ extends Option
+ {
+ private Class mode;
+
+ public ModeOption(char shortName, String description, Class mode)
+ {
+ super(shortName, description);
+ this.mode = mode;
+ }
+
+ public ModeOption(char shortName, String description, String argName,
+ Class mode)
+ {
+ super(shortName, description, argName);
+ this.mode = mode;
+ }
+
+ public void parsed(String argument) throws OptionException
+ {
+ if (operationMode != null)
+ throw new OptionException(Messages.getString("Main.ModeAlreaySet")); //$NON-NLS-1$
+ operationMode = mode;
+ // We know this is only the case for -i.
+ if (argument != null)
+ setArchiveFile(argument);
+ }
+ }
+
+ private class JarParser extends ClasspathToolParser
+ {
+ public JarParser(String name)
+ {
+ super(name);
+ }
+
+ protected void validate() throws OptionException
+ {
+ if (operationMode == null)
+ throw new OptionException(Messages.getString("Main.MustSpecify")); //$NON-NLS-1$
+ if (changedDirectory != null)
+ throw new OptionException(Messages.getString("Main.TwoArgsReqd")); //$NON-NLS-1$
+ if (! wantManifest && manifestFile != null)
+ throw new OptionException(Messages.getString("Main.CantHaveBoth")); //$NON-NLS-1$
+ if (operationMode == Indexer.class)
+ {
+ // Some extra validation for -i.
+ if (! entries.isEmpty())
+ throw new OptionException(Messages.getString("Main.NoFilesWithi")); //$NON-NLS-1$
+ if (! wantManifest)
+ throw new OptionException(Messages.getString("Main.NoMAndi")); //$NON-NLS-1$
+ if (manifestFile != null)
+ throw new OptionException(Messages.getString("Main.AnotherNomAndi")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private ClasspathToolParser initializeParser()
+ {
+ ClasspathToolParser p = new JarParser("jar"); //$NON-NLS-1$
+ p.setHeader(Messages.getString("Main.Usage")); //$NON-NLS-1$
+
+ OptionGroup grp = new OptionGroup(Messages.getString("Main.OpMode")); //$NON-NLS-1$
+ grp.add(new ModeOption('c', Messages.getString("Main.Create"), Creator.class)); //$NON-NLS-1$
+ grp.add(new ModeOption('x', Messages.getString("Main.Extract"), Extractor.class)); //$NON-NLS-1$
+ grp.add(new ModeOption('t', Messages.getString("Main.List"), Lister.class)); //$NON-NLS-1$
+ grp.add(new ModeOption('u', Messages.getString("Main.Update"), Updater.class)); //$NON-NLS-1$
+ // Note that -i works in-place and explicitly requires a file name.
+ grp.add(new ModeOption('i', Messages.getString("Main.Index"), Messages.getString("Main.FileArg"), Indexer.class)); //$NON-NLS-1$ //$NON-NLS-2$
+ p.add(grp);
+
+ grp = new OptionGroup(Messages.getString("Main.OpMods")); //$NON-NLS-1$
+ grp.add(new Option('f', Messages.getString("Main.ArchiveName"), Messages.getString("Main.FileArg2")) //$NON-NLS-1$ //$NON-NLS-2$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ setArchiveFile(argument);
+ }
+ });
+ grp.add(new Option('0', Messages.getString("Main.NoZip")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ storageMode = ZipOutputStream.STORED;
+ }
+ });
+ grp.add(new Option('v', Messages.getString("Main.Verbose")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ grp.add(new Option('M', Messages.getString("Main.NoManifest")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ wantManifest = false;
+ }
+ });
+ grp.add(new Option('m', Messages.getString("Main.ManifestName"), Messages.getString("Main.ManifestArgName")) //$NON-NLS-1$ //$NON-NLS-2$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ manifestFile = new File(argument);
+ }
+ });
+ // -@
+ p.add(grp);
+
+ grp = new OptionGroup(Messages.getString("Main.FileNameGroup")); //$NON-NLS-1$
+ grp.add(new Option('C', Messages.getString("Main.ChangeDir"), //$NON-NLS-1$
+ Messages.getString("Main.ChangeDirArg")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ changedDirectory = argument;
+ }
+ });
+ grp.add(new Option('@', Messages.getString("Main.Stdin"))
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ readNamesFromStdin = true;
+ }
+ });
+ p.add(grp);
+
+ return p;
+ }
+
+ private void readNames()
+ {
+ String line;
+ try
+ {
+ BufferedReader br
+ = new BufferedReader(new InputStreamReader(System.in));
+ while ((line = br.readLine()) != null)
+ entries.add(new Entry(new File(line)));
+ }
+ catch (IOException _)
+ {
+ // Ignore.
+ }
+ }
+
+ private void run(String[] args)
+ throws InstantiationException, IllegalAccessException, IOException
+ {
+ ClasspathToolParser p = initializeParser();
+ // Special hack to emulate old tar-style commands.
+ if (args.length > 0 && args[0].charAt(0) != '-')
+ args[0] = '-' + args[0];
+ p.parse(args, new HandleFile(), true);
+ if (readNamesFromStdin)
+ readNames();
+ Action t = (Action) operationMode.newInstance();
+ t.run(this);
+ }
+
+ public static void main(String[] args)
+ {
+ Main jarprogram = new Main();
+ try
+ {
+ jarprogram.run(args);
+ }
+ catch (Exception e)
+ {
+ System.err.println(Messages.getString("Main.InternalError")); //$NON-NLS-1$
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Messages.java
new file mode 100644
index 000000000..ea54bd08f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- localization support for jar
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.jar.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/Updater.java b/libjava/classpath/tools/gnu/classpath/tools/jar/Updater.java
new file mode 100644
index 000000000..e1df852ff
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/Updater.java
@@ -0,0 +1,98 @@
+/* Updater.java - action to update a jar file
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+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.OutputStream;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+public class Updater
+ extends Creator
+{
+ JarFile inputJar;
+
+ protected Manifest createManifest(Main parameters) throws IOException
+ {
+ Manifest result = inputJar.getManifest();
+ if (result == null)
+ return super.createManifest(parameters);
+ if (parameters.manifestFile != null)
+ result.read(new FileInputStream(parameters.manifestFile));
+ return result;
+ }
+
+ public void run(Main parameters) throws IOException
+ {
+ // Set this early so that createManifest can use it.
+ inputJar = new JarFile(parameters.archiveFile);
+
+ // Write all the new entries to a temporary file.
+ File tmpFile = File.createTempFile("jarcopy", null,
+ parameters.archiveFile.getParentFile());
+ OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile));
+ writeCommandLineEntries(parameters, os);
+
+ // Now read the old file and copy extra entries to the new file.
+ Enumeration e = inputJar.entries();
+ while (e.hasMoreElements())
+ {
+ ZipEntry entry = (ZipEntry) e.nextElement();
+ if (writtenItems.contains(entry.getName()))
+ continue;
+ writeFile(entry.isDirectory(), inputJar.getInputStream(entry),
+ entry.getName(), parameters.verbose);
+ }
+
+ close();
+ if (!tmpFile.renameTo(parameters.archiveFile))
+ {
+ throw new IOException("Couldn't rename new JAR file " + tmpFile +
+ "to " + parameters.archiveFile);
+ }
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jar/WorkSet.java b/libjava/classpath/tools/gnu/classpath/tools/jar/WorkSet.java
new file mode 100644
index 000000000..d4b7f1eac
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jar/WorkSet.java
@@ -0,0 +1,83 @@
+/* WorkSet.java -- Helper to track what files to work on
+ Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.jar;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+public class WorkSet
+{
+ private HashSet<String> allItems;
+
+ private void initSet(ArrayList<Entry> entries)
+ {
+ if (entries == null || entries.isEmpty())
+ return;
+ allItems = new HashSet<String>();
+ for (Entry entry : entries)
+ {
+ int len = entry.name.length();
+ while (len > 0 && entry.name.charAt(len - 1) == '/')
+ --len;
+ String name = entry.name.substring(0, len);
+ allItems.add(name);
+ }
+ }
+
+ public WorkSet(ArrayList<Entry> entries)
+ {
+ initSet(entries);
+ }
+
+ public boolean contains(String filename)
+ {
+ if (allItems == null)
+ return true;
+ while (filename.length() > 0)
+ {
+ if (allItems.contains(filename))
+ return true;
+ int index = filename.lastIndexOf('/');
+ if (index == -1)
+ break;
+ filename = filename.substring(0, index);
+ }
+ return false;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jarsigner/HashUtils.java b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/HashUtils.java
new file mode 100644
index 000000000..c9921dd70
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/HashUtils.java
@@ -0,0 +1,124 @@
+/* Utils.java -- Utility methods for JAR file signing/verification
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.jarsigner;
+
+import gnu.classpath.Configuration;
+import gnu.java.security.hash.Sha160;
+import gnu.java.util.Base64;
+import gnu.java.util.jar.JarUtils;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.logging.Logger;
+
+/**
+ * Collection of utility methods used in JAR file signing and verification.
+ */
+class HashUtils
+{
+ private static final Logger log = Logger.getLogger(HashUtils.class.getName());
+ private Sha160 sha = new Sha160();
+
+ // default 0-arguments constructor
+
+ /**
+ * @param stream the input stream to digest.
+ * @return a base-64 representation of the resulting SHA-1 digest of the
+ * contents of the designated input stream.
+ * @throws IOException if an I/O related exception occurs during the process.
+ */
+ String hashStream(InputStream stream) throws IOException
+ {
+ BufferedInputStream bis = new BufferedInputStream(stream, 4096);
+ byte[] buffer = new byte[4096];
+ int count = 0;
+ int n;
+ while ((n = bis.read(buffer)) != - 1)
+ if (n > 0)
+ {
+ sha.update(buffer, 0, n);
+ count += n;
+ }
+ byte[] hash = sha.digest();
+ if (Configuration.DEBUG)
+ log.finest("Hashed " + count + " byte(s)");
+ String result = Base64.encode(hash);
+ return result;
+ }
+
+ /**
+ * @param ba the byte array to digest.
+ * @return a base-64 representation of the resulting SHA-1 digest of the
+ * contents of the designated buffer.
+ */
+ String hashByteArray(byte[] ba) throws IOException
+ {
+ sha.update(ba);
+ byte[] hash = sha.digest();
+ if (Configuration.DEBUG)
+ log.finest("Hashed " + ba.length + " byte(s)");
+ String result = Base64.encode(hash);
+ return result;
+ }
+
+ /**
+ * @param name the JAR entry name
+ * @param entryHash the hash of the entry file which appears in the
+ * manifest.
+ * @return the base-64 encoded form of the hash of the corresponding Manifest
+ * JAR entry which will appear in the SF file under the entry with the
+ * same name.
+ * @throws UnsupportedEncodingException If UTF-8 character encoding is not
+ * supported on this platform.
+ */
+ String hashManifestEntry(String name, String entryHash)
+ throws UnsupportedEncodingException
+ {
+ sha.update((JarUtils.NAME + ": " + name).getBytes("UTF-8"));
+ sha.update(JarUtils.CRLF);
+ sha.update((Main.DIGEST + ": " + entryHash).getBytes("UTF-8"));
+ sha.update(JarUtils.CRLF);
+ sha.update(JarUtils.CRLF);
+ byte[] sfHash = sha.digest();
+ String result = Base64.encode(sfHash);
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarSigner.java b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarSigner.java
new file mode 100644
index 000000000..87db8b952
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarSigner.java
@@ -0,0 +1,173 @@
+/* JarSigner.java -- The signing handler of the gjarsigner tool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.jarsigner;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.SystemProperties;
+import gnu.java.util.jar.JarUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.logging.Logger;
+
+/**
+ * The JAR signing handler of the <code>gjarsigner</code> tool.
+ */
+public class JarSigner
+{
+ private static final Logger log = Logger.getLogger(JarSigner.class.getName());
+ /** The owner tool of this handler. */
+ private Main main;
+
+ JarSigner(Main main)
+ {
+ super();
+
+ this.main = main;
+ }
+
+ void start() throws Exception
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ JarFile jarFile = new JarFile(main.getJarFileName());
+ SFHelper sfHelper = new SFHelper(jarFile);
+
+ sfHelper.startSigning();
+
+ // 1. compute the digests
+ for (Enumeration e = jarFile.entries(); e.hasMoreElements(); )
+ {
+ JarEntry je = (JarEntry) e.nextElement();
+ String jeName = je.getName();
+ if (jeName.equals(JarFile.MANIFEST_NAME)
+ || jeName.endsWith(File.separator))
+ continue;
+
+ sfHelper.updateEntry(je);
+ if (main.isVerbose())
+ System.out.println(Messages.getString("JarSigner.1") + jeName); //$NON-NLS-1$
+ }
+
+ sfHelper.finishSigning(main.isSectionsOnly());
+ if (main.isVerbose())
+ System.out.println(Messages.getString("JarSigner.2") + JarFile.MANIFEST_NAME); //$NON-NLS-1$
+
+ // 2. write jar entries and manifest
+ File signedJarFile = File.createTempFile("gcp-", ".jar"); //$NON-NLS-1$ //$NON-NLS-2$
+ FileOutputStream fos = new FileOutputStream(signedJarFile);
+ JarOutputStream outSignedJarFile = new JarOutputStream(fos,
+ sfHelper.getManifest());
+ for (Enumeration e = jarFile.entries(); e.hasMoreElements(); )
+ {
+ JarEntry je = (JarEntry) e.nextElement();
+ String jeName = je.getName();
+ if (jeName.equals(JarFile.MANIFEST_NAME)
+ || jeName.endsWith(File.separator))
+ continue;
+
+ log.finest("Processing " + jeName); //$NON-NLS-1$
+ JarEntry newEntry = new JarEntry(jeName);
+ newEntry.setTime(je.getTime());
+ outSignedJarFile.putNextEntry(newEntry);
+ InputStream jeis = jarFile.getInputStream(je);
+ copyFromTo(jeis, outSignedJarFile);
+ }
+
+ // 3. create the .SF file
+ String signaturesFileName = main.getSigFileName();
+ String sfFileName = JarUtils.META_INF + signaturesFileName
+ + JarUtils.SF_SUFFIX;
+ if (Configuration.DEBUG)
+ log.fine("Processing " + sfFileName); //$NON-NLS-1$
+ JarEntry sfEntry = new JarEntry(sfFileName);
+ sfEntry.setTime(System.currentTimeMillis());
+ outSignedJarFile.putNextEntry(sfEntry);
+ sfHelper.writeSF(outSignedJarFile);
+ if (Configuration.DEBUG)
+ log.fine("Created .SF file"); //$NON-NLS-1$
+ if (main.isVerbose())
+ System.out.println(Messages.getString("JarSigner.8") + sfFileName); //$NON-NLS-1$
+
+ // 4. create the .DSA file
+ String dsaFileName = JarUtils.META_INF + signaturesFileName
+ + JarUtils.DSA_SUFFIX;
+ if (Configuration.DEBUG)
+ log.fine("Processing " + dsaFileName); //$NON-NLS-1$
+ JarEntry dsaEntry = new JarEntry(dsaFileName);
+ dsaEntry.setTime(System.currentTimeMillis());
+ outSignedJarFile.putNextEntry(dsaEntry);
+ sfHelper.writeDSA(outSignedJarFile,
+ main.getSignerPrivateKey(),
+ main.getSignerCertificateChain(),
+ main.isInternalSF());
+ if (Configuration.DEBUG)
+ log.fine("Created .DSA file"); //$NON-NLS-1$
+ if (main.isVerbose())
+ System.out.println(Messages.getString("JarSigner.8") + dsaFileName); //$NON-NLS-1$
+
+ // cleanup
+ outSignedJarFile.close();
+ fos.close();
+ signedJarFile.renameTo(new File(main.getSignedJarFileName()));
+ if (Configuration.DEBUG)
+ log.fine("Renamed signed JAR file"); //$NON-NLS-1$
+ if (main.isVerbose())
+ System.out.println(SystemProperties.getProperty("line.separator") //$NON-NLS-1$
+ + Messages.getString("JarSigner.14")); //$NON-NLS-1$
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ private void copyFromTo(InputStream in, JarOutputStream out)
+ throws IOException
+ {
+ byte[] buffer = new byte[8192];
+ int n;
+ while ((n = in.read(buffer)) != -1)
+ if (n > 0)
+ out.write(buffer, 0, n);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarVerifier.java b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarVerifier.java
new file mode 100644
index 000000000..b920d74c1
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/JarVerifier.java
@@ -0,0 +1,343 @@
+/* JarVerifier.java -- The verification handler of the gjarsigner tool
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.jarsigner;
+
+import gnu.classpath.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.pkcs.PKCS7SignedData;
+import gnu.java.security.pkcs.SignerInfo;
+import gnu.java.security.sig.ISignature;
+import gnu.java.security.sig.ISignatureCodec;
+import gnu.java.security.sig.dss.DSSSignature;
+import gnu.java.security.sig.dss.DSSSignatureX509Codec;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5Signature;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+import gnu.java.security.util.Util;
+import gnu.java.util.jar.JarUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Logger;
+import java.util.zip.ZipException;
+
+/**
+ * The JAR verification handler of the <code>gjarsigner</code> tool.
+ */
+public class JarVerifier
+{
+ private static final Logger log = Logger.getLogger(JarVerifier.class.getName());
+ /** The owner tool of this handler. */
+ private Main main;
+ private HashUtils util = new HashUtils();
+ /** The JAR file to verify. */
+ private JarFile jarFile;
+ /** Map of jar entry names to their hash. */
+ private Map<String, String> entryHashes = new HashMap<String, String>();
+
+ JarVerifier(Main main)
+ {
+ super();
+
+ this.main = main;
+ }
+
+ void start() throws Exception
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ String jarFileName = main.getJarFileName();
+ jarFile = new JarFile(jarFileName);
+
+ // 1. find all signature (.SF) files
+ List<String> sfFiles = new ArrayList<String>();
+ for (Enumeration e = jarFile.entries(); e.hasMoreElements(); )
+ {
+ JarEntry je = (JarEntry) e.nextElement();
+ String jeName = je.getName();
+ if (! (jeName.startsWith(JarUtils.META_INF)
+ && jeName.endsWith(JarUtils.SF_SUFFIX)))
+ continue;
+
+ // only interested in .SF files in, and not deeper than, META-INF
+ String[] jeNameParts = jeName.split("/"); //$NON-NLS-1$
+ if (jeNameParts.length != 2)
+ continue;
+
+ String sfName = jeNameParts[1];
+ String sigFileName = sfName.substring(0, sfName.length() - 3);
+ sfFiles.add(sigFileName);
+ }
+
+ // 2. verify each one
+ if (sfFiles.isEmpty())
+ System.out.println(Messages.getString("JarVerifier.2")); //$NON-NLS-1$
+ else
+ {
+ int limit = sfFiles.size();
+ int count = 0;
+ for (String alias : sfFiles)
+ if (verifySF(alias))
+ if (verifySFEntries(alias))
+ count++;
+
+ if (count == 0)
+ System.out.println(Messages.getString("JarVerifier.3")); //$NON-NLS-1$
+ else if (count != limit)
+ System.out.println(Messages.getFormattedString("JarVerifier.4", //$NON-NLS-1$
+ new Integer[] {Integer.valueOf(count),
+ Integer.valueOf(limit)}));
+ else
+ System.out.println(Messages.getFormattedString("JarVerifier.7", //$NON-NLS-1$
+ Integer.valueOf(limit)));
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ /**
+ * @param sigFileName the name of the signature file; i.e. the name to use for
+ * both the .SF and .DSA files.
+ * @return <code>true</code> if the designated file-name (usually a key-store
+ * <i>alias</i> name) has been successfully checked as the signer of the
+ * corresponding <code>.SF</code> file. Returns <code>false</code> otherwise.
+ * @throws IOException
+ * @throws ZipException
+ * @throws CertificateException
+ * @throws CRLException
+ */
+ private boolean verifySF(String sigFileName) throws CRLException,
+ CertificateException, ZipException, IOException
+ {
+ if (Configuration.DEBUG)
+ {
+ log.entering(this.getClass().getName(), "verifySF"); //$NON-NLS-1$
+ log.fine("About to verify signature of " + sigFileName + "..."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ // 1. find the corresponding .DSA file for this .SF file
+ JarEntry dsaEntry = jarFile.getJarEntry(JarUtils.META_INF + sigFileName
+ + JarUtils.DSA_SUFFIX);
+ if (dsaEntry == null)
+ throw new SecurityException(Messages.getFormattedString("JarVerifier.13", //$NON-NLS-1$
+ sigFileName));
+ // 2. read the .DSA file contents as a PKCS7 SignedData
+ InputStream in = jarFile.getInputStream(dsaEntry);
+ PKCS7SignedData pkcs7SignedData = new PKCS7SignedData(in);
+
+ // 4. get the encrypted digest octet string from the first SignerInfo
+ // this octet string is the digital signature of the .SF file contents
+ Set signerInfos = pkcs7SignedData.getSignerInfos();
+ if (signerInfos == null || signerInfos.isEmpty())
+ throw new SecurityException(Messages.getString("JarVerifier.14")); //$NON-NLS-1$
+
+ SignerInfo signerInfo = (SignerInfo) signerInfos.iterator().next();
+ byte[] encryptedDigest = signerInfo.getEncryptedDigest();
+ if (encryptedDigest == null)
+ throw new SecurityException(Messages.getString("JarVerifier.16")); //$NON-NLS-1$
+
+ if (Configuration.DEBUG)
+ log.fine("\n" + Util.dumpString(encryptedDigest, "--- signedSFBytes ")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // 5. get the signer public key
+ Certificate cert = pkcs7SignedData.getCertificates()[0];
+ PublicKey verifierKey = cert.getPublicKey();
+ if (Configuration.DEBUG)
+ log.fine("--- verifier public key = " + verifierKey); //$NON-NLS-1$
+
+ // 6. verify the signature file signature
+ OID digestEncryptionAlgorithmOID = signerInfo.getDigestEncryptionAlgorithmId();
+ ISignature signatureAlgorithm;
+ ISignatureCodec signatureCodec;
+ if (digestEncryptionAlgorithmOID.equals(Main.DSA_SIGNATURE_OID))
+ {
+ signatureAlgorithm = new DSSSignature();
+ signatureCodec = new DSSSignatureX509Codec();
+ }
+ else
+ {
+ signatureAlgorithm = new RSAPKCS1V1_5Signature(Registry.MD5_HASH);
+ signatureCodec = new RSAPKCS1V1_5SignatureX509Codec();
+ }
+
+ Map signatureAttributes = new HashMap();
+ signatureAttributes.put(ISignature.VERIFIER_KEY, verifierKey);
+ signatureAlgorithm.setupVerify(signatureAttributes);
+
+ Object herSignature = signatureCodec.decodeSignature(encryptedDigest);
+
+ // 7. verify the signature file contents
+ JarEntry sfEntry = jarFile.getJarEntry(JarUtils.META_INF + sigFileName
+ + JarUtils.SF_SUFFIX);
+ in = jarFile.getInputStream(sfEntry);
+ byte[] buffer = new byte[2048];
+ int n;
+ while ((n = in.read(buffer)) != -1)
+ if (n > 0)
+ signatureAlgorithm.update(buffer, 0, n);
+
+ boolean result = signatureAlgorithm.verify(herSignature);
+ if (Configuration.DEBUG)
+ {
+ log.fine("Signature block [" + sigFileName + "] is " //$NON-NLS-1$ //$NON-NLS-2$
+ + (result ? "" : "NOT ") + "OK"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ log.exiting(this.getClass().getName(), "verifySF", Boolean.valueOf(result)); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ /**
+ * This method is called after at least one signer (usually a key-store
+ * <code>alias</code> name) was found to be trusted; i.e. his/her signature
+ * block in the corresponding <code>.DSA</code> file was successfully
+ * verified using his/her public key.
+ * <p>
+ * This method, uses the contents of the corresponding <code>.SF</code> file
+ * to compute and verify the hashes of the manifest entries in the JAR file.
+ *
+ * @param alias the name of the signature file; i.e. the name to use for both
+ * the .SF and .DSA files.
+ * @return <code>true</code> if all the entries in the corresponding
+ * <code>.SF</code> file have the same hash values as their
+ * alter-ego in the <i>manifest</i> file of the JAR file inquestion.
+ * @throws IOException if an I/O related exception occurs during the process.
+ */
+ private boolean verifySFEntries(String alias) throws IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "verifySFEntries"); //$NON-NLS-1$
+ // 1. read the signature file
+ JarEntry jarEntry = jarFile.getJarEntry(JarUtils.META_INF + alias
+ + JarUtils.SF_SUFFIX);
+ InputStream in = jarFile.getInputStream(jarEntry);
+ Attributes attr = new Attributes();
+ Map<String, Attributes> entries = new HashMap<String, Attributes>();
+ JarUtils.readSFManifest(attr, entries, in);
+
+ // 2. The .SF file by default includes a header containing a hash of the
+ // entire manifest file. When the header is present, then the verification
+ // can check to see whether or not the hash in the header indeed matches
+ // the hash of the manifest file.
+ boolean result = false;
+ String hash = attr.getValue(Main.DIGEST_MANIFEST_ATTR);
+ if (hash != null)
+ result = verifyManifest(hash);
+
+ // A verification is still considered successful if none of the files that
+ // were in the JAR file when the signature was generated have been changed
+ // since then, which is the case if the hashes in the non-header sections
+ // of the .SF file equal the hashes of the corresponding sections in the
+ // manifest file.
+ //
+ // 3. Read each file in the JAR file that has an entry in the .SF file.
+ // While reading, compute the file's digest, and then compare the result
+ // with the digest for this file in the manifest section. The digests
+ // should be the same, or verification fails.
+ if (! result)
+ for (Entry<String, Attributes> me : entries.entrySet())
+ {
+ String name = me.getKey();
+ attr = me.getValue();
+ hash = attr.getValue(Main.DIGEST_ATTR);
+ result = verifySFEntry(name, hash);
+ if (! result)
+ break;
+ }
+
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "verifySFEntries", //$NON-NLS-1$
+ Boolean.valueOf(result));
+ return result;
+ }
+
+ /**
+ * @param hash Base-64 encoded form of the manifest's digest.
+ * @return <code>true</code> if our computation of the manifest's hash
+ * matches the given value; <code>false</code> otherwise.
+ * @throws IOException if unable to acquire the JAR's manifest entry.
+ */
+ private boolean verifyManifest(String hash) throws IOException
+ {
+ return verifySFEntry(JarFile.MANIFEST_NAME, hash);
+ }
+
+ /**
+ * @param name the name of a JAR entry to verify.
+ * @param hash Base-64 encoded form of the designated entry's digest.
+ * @return <code>true</code> if our computation of the JAR entry's hash
+ * matches the given value; <code>false</code> otherwise.
+ * @throws IOException if an exception occurs while returning the entry's
+ * input stream.
+ */
+ private boolean verifySFEntry(String name, String hash) throws IOException
+ {
+ String expectedValue = getEntryHash(JarFile.MANIFEST_NAME);
+ boolean result = expectedValue.equalsIgnoreCase(hash);
+ if (Configuration.DEBUG)
+ log.fine("Is " + name + " OK? " + result); //$NON-NLS-1$ //$NON-NLS-2$
+ return result;
+ }
+
+ private String getEntryHash(String entryName) throws IOException
+ {
+ String result = (String) entryHashes.get(entryName);
+ if (result == null)
+ {
+ JarEntry manifest = jarFile.getJarEntry(entryName);
+ InputStream in = jarFile.getInputStream(manifest);
+ result = util.hashStream(in);
+ entryHashes.put(entryName, result);
+ }
+
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jarsigner/Main.java b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/Main.java
new file mode 100644
index 000000000..c7fb5856a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/Main.java
@@ -0,0 +1,689 @@
+/* Main.java -- JAR signing and verification tool not unlike jarsigner
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.jarsigner;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.SystemProperties;
+import gnu.classpath.tools.common.CallbackUtil;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.common.ProviderUtil;
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.javax.security.auth.callback.ConsoleCallbackHandler;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.jar.Attributes.Name;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The GNU Classpath implementation of the <i>jarsigner</i> tool.
+ * <p>
+ * The <i>jarsigner</i> tool is used to sign and verify JAR (Java ARchive)
+ * files.
+ * <p>
+ * This implementation is intended to be compatible with the behaviour
+ * described in the public documentation of the same tool included in JDK 1.4.
+ */
+public class Main
+{
+ protected static final Logger log = Logger.getLogger(Main.class.getName());
+ static final String KEYTOOL_TOOL = "jarsigner"; //$NON-NLS-1$
+ private static final Locale EN_US_LOCALE = new Locale("en", "US"); //$NON-NLS-1$ //$NON-NLS-2$
+ static final String DIGEST = "SHA1-Digest"; //$NON-NLS-1$
+ static final String DIGEST_MANIFEST = "SHA1-Digest-Manifest"; //$NON-NLS-1$
+ static final Name DIGEST_ATTR = new Name(DIGEST);
+ static final Name DIGEST_MANIFEST_ATTR = new Name(DIGEST_MANIFEST);
+ static final OID DSA_SIGNATURE_OID = new OID(Registry.DSA_OID_STRING);
+ static final OID RSA_SIGNATURE_OID = new OID(Registry.RSA_OID_STRING);
+
+ protected boolean verify;
+ protected String ksURL;
+ protected String ksType;
+ protected String password;
+ protected String ksPassword;
+ protected String sigFileName;
+ protected String signedJarFileName;
+ protected boolean verbose;
+ protected boolean certs;
+ protected boolean internalSF;
+ protected boolean sectionsOnly;
+ protected String providerClassName;
+ protected String jarFileName;
+ protected String alias;
+
+ protected Provider provider;
+ private boolean providerInstalled;
+ private char[] ksPasswordChars;
+ private KeyStore store;
+ private char[] passwordChars;
+ private PrivateKey signerPrivateKey;
+ private Certificate[] signerCertificateChain;
+ /** The callback handler to use when needing to interact with user. */
+ private CallbackHandler handler;
+ /** The command line parser. */
+ private ToolParser cmdLineParser;
+ protected ArrayList<String> fileAndAlias = new ArrayList<String>();
+
+ private Main()
+ {
+ super();
+ }
+
+ public static final void main(String[] args)
+ {
+ if (Configuration.DEBUG)
+ log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$
+ Main tool = new Main();
+ int result = 1;
+ try
+ {
+ tool.processArgs(args);
+ tool.start();
+ result = 0;
+ }
+ catch (SecurityException x)
+ {
+ if (Configuration.DEBUG)
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getString("Main.7") + x.getMessage()); //$NON-NLS-1$
+ }
+ catch (Exception x)
+ {
+ if (Configuration.DEBUG)
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getString("Main.9") + x); //$NON-NLS-1$
+ }
+ finally
+ {
+ tool.teardown();
+ }
+ if (Configuration.DEBUG)
+ log.exiting(Main.class.getName(), "main", Integer.valueOf(result)); //$NON-NLS-1$
+ System.exit(result);
+ }
+
+ /**
+ * Read the command line arguments setting the tool's parameters in
+ * preparation for the user desired action.
+ *
+ * @param args an array of options (strings).
+ * @throws Exception if an exception occurs during the process.
+ */
+ private void processArgs(String[] args) throws Exception
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$
+ cmdLineParser = new ToolParser();
+ cmdLineParser.initializeParser();
+ cmdLineParser.parse(args, new ToolParserCallback());
+
+ setupCommonParams();
+ if (verify)
+ {
+ if (Configuration.DEBUG)
+ {
+ log.fine("Will verify with the following parameters:"); //$NON-NLS-1$
+ log.fine(" jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine("Options:"); //$NON-NLS-1$
+ log.fine(" provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" verbose ? " + verbose); //$NON-NLS-1$
+ log.fine(" certs ? " + certs); //$NON-NLS-1$
+ log.fine(" internalsf ? " + internalSF); //$NON-NLS-1$
+ log.fine(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$
+ }
+ }
+ else // sign
+ {
+ setupSigningParams();
+ if (Configuration.DEBUG)
+ {
+ log.fine("Will sign with the following parameters:"); //$NON-NLS-1$
+ log.fine(" jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" alias = '" + alias + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine("Options:"); //$NON-NLS-1$
+ log.fine(" keystore = '" + ksURL + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" storetype = '" + ksType + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" storepass = '" + ksPassword + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" keypass = '" + password + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" sigfile = '" + sigFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" signedjar = '" + signedJarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.fine(" verbose ? " + verbose); //$NON-NLS-1$
+ log.fine(" internalsf ? " + internalSF); //$NON-NLS-1$
+ log.fine(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$
+ }
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "processArgs"); //$NON-NLS-1$
+ }
+
+ /**
+ * Invokes the <code>start()</code> method of the concrete handler.
+ * <p>
+ * Depending on the result of processing the command line arguments, this
+ * handler may be one for signing the jar, or verifying it.
+ *
+ * @throws Exception if an exception occurs during the process.
+ */
+ private void start() throws Exception
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ if (verify)
+ {
+ JarVerifier jv = new JarVerifier(this);
+ jv.start();
+ }
+ else
+ {
+ JarSigner js = new JarSigner(this);
+ js.start();
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ /**
+ * Ensures that the underlying JVM is left in the same state as we found it
+ * when we first launched the tool. Specifically, if we have installed a new
+ * security provider then now is the time to remove it.
+ * <p>
+ * Note (rsn): this may not be necessary if we terminate the JVM; i.e. call
+ * {@link System#exit(int)} at the end of the tool's invocation. Nevertheless
+ * it's good practive to return the JVM to its initial state.
+ */
+ private void teardown()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ if (providerInstalled)
+ ProviderUtil.removeProvider(provider.getName());
+
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ }
+
+ /**
+ * After processing the command line arguments, this method is invoked to
+ * process the common parameters which may have been encountered among the
+ * actual arguments.
+ * <p>
+ * Common parameters are those which are allowed in both signing and
+ * verification modes.
+ *
+ * @throws InstantiationException if a security provider class name is
+ * specified but that class name is that of either an interface or
+ * an abstract class.
+ * @throws IllegalAccessException if a security provider class name is
+ * specified but no 0-arguments constructor is defined for that
+ * class.
+ * @throws ClassNotFoundException if a security provider class name is
+ * specified but no such class was found in the classpath.
+ * @throws IOException if the JAR file name for signing, or verifying, does
+ * not exist, exists but denotes a directory, or is not readable.
+ */
+ private void setupCommonParams() throws InstantiationException,
+ IllegalAccessException, ClassNotFoundException, IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$
+ File jar = new File(jarFileName);
+ if (! jar.exists())
+ throw new FileNotFoundException(jarFileName);
+
+ if (jar.isDirectory())
+ throw new IOException(Messages.getFormattedString("Main.70", jarFileName)); //$NON-NLS-1$
+
+ if (! jar.canRead())
+ throw new IOException(Messages.getFormattedString("Main.72", jarFileName)); //$NON-NLS-1$ //$NON-NLS-2$
+
+ if (providerClassName != null && providerClassName.length() > 0)
+ {
+ provider = (Provider) Class.forName(providerClassName).newInstance();
+ // is it already installed?
+ String providerName = provider.getName();
+ Provider installedProvider = Security.getProvider(providerName);
+ if (installedProvider != null)
+ {
+ if (Configuration.DEBUG)
+ log.finer("Provider " + providerName + " is already installed"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ else // install it
+ installNewProvider();
+ }
+
+ if (! verbose && certs)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Option <certs> is set but <verbose> is not. Ignored"); //$NON-NLS-1$
+ certs = false;
+ }
+
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$
+ }
+
+ /**
+ * Install the user defined security provider in the underlying JVM.
+ * <p>
+ * Also record this fact so we can remove it when we exit the tool.
+ */
+ private void installNewProvider()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "installNewProvider"); //$NON-NLS-1$
+ providerInstalled = ProviderUtil.addProvider(provider) != -1;
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "installNewProvider"); //$NON-NLS-1$
+ }
+
+ /**
+ * After processing the command line arguments, this method is invoked to
+ * process the parameters which may have been encountered among the actual
+ * arguments, and which are specific to the signing action of the tool.
+ *
+ * @throws KeyStoreException if no implementation of the designated (or
+ * default type) of a key store is availabe.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws NoSuchAlgorithmException if an implementation of an algorithm used
+ * by the key store is not available.
+ * @throws CertificateException if an exception occurs while reading a
+ * certificate from the key store.
+ * @throws UnsupportedCallbackException if no implementation of a password
+ * callback is available.
+ * @throws UnrecoverableKeyException if the wrong password was used to unlock
+ * the key store.
+ * @throws SecurityException if the designated alias is not known to the key
+ * store or is not an Alias of a Key Entry.
+ */
+ private void setupSigningParams() throws KeyStoreException, IOException,
+ NoSuchAlgorithmException, CertificateException,
+ UnsupportedCallbackException, UnrecoverableKeyException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "setupSigningParams"); //$NON-NLS-1$
+ if (ksURL == null || ksURL.trim().length() == 0)
+ {
+ String userHome = SystemProperties.getProperty("user.home"); //$NON-NLS-1$
+ if (userHome == null || userHome.trim().length() == 0)
+ throw new SecurityException(Messages.getString("Main.85")); //$NON-NLS-1$
+
+ ksURL = "file:" + userHome.trim() + "/.keystore"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ else
+ {
+ ksURL = ksURL.trim();
+ if (ksURL.indexOf(":") == -1) //$NON-NLS-1$
+ ksURL = "file:" + ksURL; //$NON-NLS-1$
+ }
+
+ if (ksType == null || ksType.trim().length() == 0)
+ ksType = KeyStore.getDefaultType();
+ else
+ ksType = ksType.trim();
+
+ store = KeyStore.getInstance(ksType);
+
+ if (ksPassword == null)
+ {
+ // ask the user to provide one
+ PasswordCallback pcb = new PasswordCallback(Messages.getString("Main.92"), //$NON-NLS-1$
+ false);
+ getCallbackHandler().handle(new Callback[] { pcb });
+ ksPasswordChars = pcb.getPassword();
+ }
+ else
+ ksPasswordChars = ksPassword.toCharArray();
+
+ URL url = new URL(ksURL);
+ InputStream stream = url.openStream();
+ store.load(stream, ksPasswordChars);
+
+ if (! store.containsAlias(alias))
+ throw new SecurityException(Messages.getFormattedString("Main.6", alias)); //$NON-NLS-1$
+
+ if (! store.isKeyEntry(alias))
+ throw new SecurityException(Messages.getFormattedString("Main.95", alias)); //$NON-NLS-1$
+
+ Key key;
+ if (password == null)
+ {
+ passwordChars = ksPasswordChars;
+ try
+ {
+ key = store.getKey(alias, passwordChars);
+ }
+ catch (UnrecoverableKeyException x)
+ {
+ // ask the user to provide one
+ String prompt = Messages.getFormattedString("Main.97", alias); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(prompt, false);
+ getCallbackHandler().handle(new Callback[] { pcb });
+ passwordChars = pcb.getPassword();
+ // take 2
+ key = store.getKey(alias, passwordChars);
+ }
+ }
+ else
+ {
+ passwordChars = password.toCharArray();
+ key = store.getKey(alias, passwordChars);
+ }
+
+ if (! (key instanceof PrivateKey))
+ throw new SecurityException(Messages.getFormattedString("Main.99", alias)); //$NON-NLS-1$
+
+ signerPrivateKey = (PrivateKey) key;
+ signerCertificateChain = store.getCertificateChain(alias);
+ if (Configuration.DEBUG)
+ log.fine(String.valueOf(signerCertificateChain));
+
+ if (sigFileName == null)
+ sigFileName = alias;
+
+ sigFileName = sigFileName.toUpperCase(EN_US_LOCALE);
+ if (sigFileName.length() > 8)
+ sigFileName = sigFileName.substring(0, 8);
+
+ char[] chars = sigFileName.toCharArray();
+ for (int i = 0; i < chars.length; i++)
+ {
+ char c = chars[i];
+ if (! (Character.isLetter(c)
+ || Character.isDigit(c)
+ || c == '_'
+ || c == '-'))
+ chars[i] = '_';
+ }
+
+ sigFileName = new String(chars);
+
+ if (signedJarFileName == null)
+ signedJarFileName = jarFileName;
+
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "setupSigningParams"); //$NON-NLS-1$
+ }
+
+ boolean isVerbose()
+ {
+ return verbose;
+ }
+
+ boolean isCerts()
+ {
+ return certs;
+ }
+
+ String getSigFileName()
+ {
+ return this.sigFileName;
+ }
+
+ String getJarFileName()
+ {
+ return this.jarFileName;
+ }
+
+ boolean isSectionsOnly()
+ {
+ return this.sectionsOnly;
+ }
+
+ boolean isInternalSF()
+ {
+ return this.internalSF;
+ }
+
+ PrivateKey getSignerPrivateKey()
+ {
+ return this.signerPrivateKey;
+ }
+
+ Certificate[] getSignerCertificateChain()
+ {
+ return signerCertificateChain;
+ }
+
+ String getSignedJarFileName()
+ {
+ return this.signedJarFileName;
+ }
+
+ /**
+ * Return a CallbackHandler which uses the Console (System.in and System.out)
+ * for interacting with the user.
+ * <p>
+ * This method first finds all currently installed security providers capable
+ * of providing such service and then in turn attempts to instantiate the
+ * handler from those providers. As soon as one provider returns a non-null
+ * instance of the callback handler, the search stops and that instance is
+ * set to be used from now on.
+ * <p>
+ * If no installed providers were found, this method falls back on the GNU
+ * provider, by-passing the Security search mechanism. The default console
+ * callback handler implementation is {@link ConsoleCallbackHandler}.
+ *
+ * @return a console-based {@link CallbackHandler}.
+ */
+ protected CallbackHandler getCallbackHandler()
+ {
+ if (handler == null)
+ handler = CallbackUtil.getConsoleHandler();
+
+ return handler;
+ }
+
+ private class ToolParserCallback
+ extends FileArgumentCallback
+ {
+ public void notifyFile(String fileArgument)
+ {
+ fileAndAlias.add(fileArgument);
+ }
+ }
+
+ private class ToolParser
+ extends ClasspathToolParser
+ {
+ public ToolParser()
+ {
+ super(KEYTOOL_TOOL, true);
+ }
+
+ protected void validate() throws OptionException
+ {
+ if (fileAndAlias.size() < 1)
+ throw new OptionException(Messages.getString("Main.133")); //$NON-NLS-1$
+
+ jarFileName = (String) fileAndAlias.get(0);
+ if (! verify) // must have an ALIAS. use "mykey" if undefined
+ if (fileAndAlias.size() < 2)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Missing ALIAS argument. Will use [mykey] instead"); //$NON-NLS-1$
+ alias = "mykey"; //$NON-NLS-1$
+ }
+ else
+ alias = fileAndAlias.get(1);
+ }
+
+ public void initializeParser()
+ {
+ setHeader(Messages.getString("Main.2")); //$NON-NLS-1$
+ setFooter(Messages.getString("Main.1")); //$NON-NLS-1$
+ OptionGroup signGroup = new OptionGroup(Messages.getString("Main.0")); //$NON-NLS-1$
+ signGroup.add(new Option("keystore", //$NON-NLS-1$
+ Messages.getString("Main.101"), //$NON-NLS-1$
+ Messages.getString("Main.102")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ksURL = argument;
+ }
+ });
+ signGroup.add(new Option("storetype", //$NON-NLS-1$
+ Messages.getString("Main.104"), //$NON-NLS-1$
+ Messages.getString("Main.105")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ksType = argument;
+ }
+ });
+ signGroup.add(new Option("storepass", //$NON-NLS-1$
+ Messages.getString("Main.107"), //$NON-NLS-1$
+ Messages.getString("Main.108")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ksPassword = argument;
+ }
+ });
+ signGroup.add(new Option("keypass", //$NON-NLS-1$
+ Messages.getString("Main.110"), //$NON-NLS-1$
+ Messages.getString("Main.111")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ password = argument;
+ }
+ });
+ signGroup.add(new Option("sigfile", //$NON-NLS-1$
+ Messages.getString("Main.113"), //$NON-NLS-1$
+ Messages.getString("Main.114")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ sigFileName = argument;
+ }
+ });
+ signGroup.add(new Option("signedjar", //$NON-NLS-1$
+ Messages.getString("Main.116"), //$NON-NLS-1$
+ Messages.getString("Main.117")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ signedJarFileName = argument;
+ }
+ });
+ add(signGroup);
+
+ OptionGroup verifyGroup = new OptionGroup(Messages.getString("Main.118")); //$NON-NLS-1$
+ verifyGroup.add(new Option("verify", //$NON-NLS-1$
+ Messages.getString("Main.120")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verify = true;
+ }
+ });
+ verifyGroup.add(new Option("certs", //$NON-NLS-1$
+ Messages.getString("Main.122")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ certs = true;
+ }
+ });
+ add(verifyGroup);
+
+ OptionGroup commonGroup = new OptionGroup(Messages.getString("Main.123")); //$NON-NLS-1$
+ commonGroup.add(new Option("verbose", //$NON-NLS-1$
+ Messages.getString("Main.125")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ commonGroup.add(new Option("internalsf", //$NON-NLS-1$
+ Messages.getString("Main.127")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ internalSF = true;
+ }
+ });
+ commonGroup.add(new Option("sectionsonly", //$NON-NLS-1$
+ Messages.getString("Main.129")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ sectionsOnly = true;
+ }
+ });
+ commonGroup.add(new Option("provider", //$NON-NLS-1$
+ Messages.getString("Main.131"), //$NON-NLS-1$
+ Messages.getString("Main.132")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ providerClassName = argument;
+ }
+ });
+ add(commonGroup);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jarsigner/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/Messages.java
new file mode 100644
index 000000000..f27f79eae
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/Messages.java
@@ -0,0 +1,119 @@
+/* Messages.java -- I18N related helper class
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.jarsigner;
+
+import gnu.classpath.Configuration;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.logging.Logger;
+
+/**
+ * An initially generated Eclipse helper class to ease the use of localized
+ * messages.
+ * <p>
+ * Enriched to handle localized message formats.
+ */
+class Messages
+{
+ private static final Logger log = Logger.getLogger(Messages.class.getName());
+ private static final String BUNDLE_NAME = "gnu.classpath.tools.jarsigner.messages";
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+ private static final Map<String, MessageFormat> CACHED_FORMATS =
+ new HashMap<String, MessageFormat>(5);
+
+ private Messages()
+ {
+ super();
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return constructMessage(key, null);
+ }
+ }
+
+ public static String getFormattedString(String key, Object args)
+ {
+ MessageFormat mf = CACHED_FORMATS.get(key);
+ if (mf == null)
+ {
+ String formatString = getString(key);
+ if (formatString.startsWith("!"))
+ return constructMessage(key, args);
+
+ mf = new MessageFormat(formatString);
+ CACHED_FORMATS.put(key, mf);
+ }
+
+ // if the argument is not an array, then build one consisting of the
+ // sole argument before passing it to the format() method
+ try
+ {
+ if (args instanceof Object[])
+ return mf.format(args);
+
+ return mf.format(new Object[] { args });
+ }
+ catch (IllegalArgumentException x)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Exception while rendering a message format keyed by ["
+ + key + "]: " + mf.toPattern());
+ return constructMessage(mf.toPattern(), args);
+ }
+ }
+
+ private static final String constructMessage(String m, Object args)
+ {
+ if (args == null)
+ return '!' + m + '!';
+
+ return '!' + m + '!' + String.valueOf(args) + '!';
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/jarsigner/SFHelper.java b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/SFHelper.java
new file mode 100644
index 000000000..9e4882f0e
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/jarsigner/SFHelper.java
@@ -0,0 +1,491 @@
+/* SFHelper -- A .SF file helper
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.jarsigner;
+
+import gnu.classpath.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.pkcs.PKCS7Data;
+import gnu.java.security.pkcs.PKCS7SignedData;
+import gnu.java.security.pkcs.SignerInfo;
+import gnu.java.security.sig.ISignature;
+import gnu.java.security.sig.ISignatureCodec;
+import gnu.java.security.sig.dss.DSSSignature;
+import gnu.java.security.sig.dss.DSSSignatureX509Codec;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5Signature;
+import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
+import gnu.java.security.util.Util;
+import gnu.java.util.jar.JarUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509CRL;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.logging.Logger;
+
+import javax.security.auth.x500.X500Principal;
+import java.security.cert.X509Certificate;
+
+/**
+ * A helper class for the .SF file found in signed jars.
+ */
+public class SFHelper
+{
+ private static final Logger log = Logger.getLogger(SFHelper.class.getName());
+ private static final int READY = 0;
+ private static final int STARTED = 1;
+ private static final int FINISHED = 2;
+ private static final int SF_GENERATED = 3;
+ private static final int DSA_GENERATED = 4;
+ /** http://asn1.elibel.tm.fr/cgi-bin/oid/display?oid=1.3.14.3.2.26&action=display */
+ private static final OID hashAlgorithmIdentifierSHA1 = new OID("1.3.14.3.2.26"); //$NON-NLS-1$
+
+ private int state;
+ private JarFile jar;
+ private Manifest manifest;
+ private Attributes sfMainAttributes;
+ private Map<String, Attributes> sfEntries;
+ private byte[] sfBytes;
+ private HashUtils util;
+
+ /**
+ * @param jar the JAR archive the .SF file belongs to.
+ */
+ public SFHelper(JarFile jar)
+ {
+ super();
+
+ this.jar = jar;
+ this.state = READY;
+ }
+
+ /**
+ * Writes the contents of the <code>.SF</code> file to the designated JAR
+ * output stream. Line-endings are platform-independent and consist of the
+ * 2-codepoint sequence <code>0x0D</code> and <code>0x0A</code>.
+ *
+ * @param jar the JAR output stream to write a <code>.SF</code> file to.
+ * @throws IOException if an I/O related exception occurs during the process.
+ */
+ void writeSF(JarOutputStream jar) throws IOException
+ {
+ if (this.state != FINISHED)
+ throw new IllegalStateException(Messages.getString("SFHelper.1")); //$NON-NLS-1$
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ JarUtils.writeSFManifest(sfMainAttributes, sfEntries, baos);
+ sfBytes = baos.toByteArray();
+ if (Configuration.DEBUG)
+ log.fine("\n" + Util.dumpString(sfBytes, "+++ sfBytes ")); //$NON-NLS-1$ //$NON-NLS-2$
+ jar.write(sfBytes);
+ jar.flush();
+
+ this.state = SF_GENERATED;
+ }
+
+ /**
+ * The contents of the .DSA file is the DER encoded form of a PKCS#7
+ * ContentInfo of the type SignedData.
+ * <p>
+ * The ContentInfo ASN.1 syntax is as described in the "PKCS#7 Cryptographic
+ * Message Syntax Standard" (RSA Labs) specifications:
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+ * }
+ *
+ * ContentType ::= OBJECT IDENTIFIER
+ * </pre>
+ * <p>
+ * The ContentType is an OID which determines the type of the contents field
+ * that follows it. For the .DSA file the OID is "1.2.840.113549.1.7.2", while
+ * the content field is the byte array representing the DER encoded form of a
+ * SignedData content-type. The ASN.1 syntax of the SignedData type is as
+ * follows:
+ * <pre>
+ * SignedData ::= SEQUENCE {
+ * version Version, -- always 1 for PKCS#7 1.5
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * contentInfo ContentInfo,
+ * certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos
+ * }
+ *
+ * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+ *
+ * SignerInfos ::= SET OF SignerInfo
+ * </pre>
+ * <p>
+ * Finally the SignerInfo is a per-signer structure. Its ASN.1 syntax looks
+ * like so:
+ * <pre>
+ * SignerInfo ::= SEQUENCE {
+ * version Version, -- always 1 for PKCS#7 1.5
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+ * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ * encryptedDigest EncryptedDigest,
+ * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+ * }
+ *
+ * EncryptedDigest ::= OCTET STRING
+ * </pre>
+ *
+ * @param jar the JAR output stream to write a <code>.DSA</code> file to.
+ * @param signerKey the private key to sign with.
+ * @param certificates the possibly null signer certificate chain.
+ * @param internalSF if <code>true</code> then include the .SF file contents
+ * in the signed .DSA file; otherwise don't.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws CRLException
+ * @throws CertificateEncodingException
+ */
+ void writeDSA(JarOutputStream jar, PrivateKey signerKey,
+ Certificate[] certificates, boolean internalSF)
+ throws IOException, CertificateEncodingException, CRLException
+ {
+ if (this.state != SF_GENERATED)
+ throw new IllegalStateException(Messages.getString("SFHelper.4")); //$NON-NLS-1$
+
+ if (Configuration.DEBUG)
+ log.fine("+++ signer private key = " + signerKey); //$NON-NLS-1$
+ ISignature signatureAlgorithm;
+ ISignatureCodec signatureCodec;
+ OID digestEncryptionAlgorithmOID;
+ if (signerKey instanceof DSAPrivateKey)
+ {
+ signatureAlgorithm = new DSSSignature();
+ signatureCodec = new DSSSignatureX509Codec();
+ digestEncryptionAlgorithmOID = Main.DSA_SIGNATURE_OID;
+ }
+ else if (signerKey instanceof RSAPrivateKey)
+ {
+ signatureAlgorithm = new RSAPKCS1V1_5Signature(Registry.MD5_HASH);
+ signatureCodec = new RSAPKCS1V1_5SignatureX509Codec();
+ digestEncryptionAlgorithmOID = Main.RSA_SIGNATURE_OID;
+ }
+ else
+ throw new SecurityException(Messages.getString("SFHelper.6")); //$NON-NLS-1$
+
+ Map signatureAttributes = new HashMap();
+ signatureAttributes.put(ISignature.SIGNER_KEY, signerKey);
+ signatureAlgorithm.setupSign(signatureAttributes);
+ signatureAlgorithm.update(sfBytes, 0, sfBytes.length);
+ Object signature = signatureAlgorithm.sign();
+ byte[] signedSFBytes = signatureCodec.encodeSignature(signature);
+ if (Configuration.DEBUG)
+ log.fine("\n" + Util.dumpString(signedSFBytes, "+++ signedSFBytes ")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Set<DERValue> digestAlgorithms = new HashSet<DERValue>();
+ List<DERValue> digestAlgorithm = new ArrayList<DERValue>(2);
+ DERValue derDigestAlgorithmOID = new DERValue(DER.OBJECT_IDENTIFIER,
+ hashAlgorithmIdentifierSHA1);
+ DERValue derDigestAlgorithmParams = new DERValue(DER.NULL, null);
+ digestAlgorithm.add(derDigestAlgorithmOID);
+ digestAlgorithm.add(derDigestAlgorithmParams);
+ DERValue derDigestAlgorithm = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ digestAlgorithm);
+ digestAlgorithms.add(derDigestAlgorithm);
+
+ // TODO (rsn): test with internalsf == true
+ PKCS7Data data = internalSF ? new PKCS7Data(sfBytes) : null;
+
+ X509CRL[] crls = null;
+
+ Set<SignerInfo> signerInfos = new HashSet<SignerInfo>();
+ X509Certificate cert = (X509Certificate) certificates[0];
+ try
+ {
+ cert.checkValidity();
+ }
+ catch (CertificateExpiredException x)
+ {
+ String issuerName = getIssuerName(cert);
+ String subjectName = getSubjectName(cert);
+ Date notAfterDate = getNotAfterDate(cert);
+ System.out.println(Messages.getFormattedString("SFHelper.0", //$NON-NLS-1$
+ new Object[] { issuerName,
+ subjectName,
+ notAfterDate }));
+ }
+ catch (CertificateNotYetValidException x)
+ {
+ String issuerName = getIssuerName(cert);
+ String subjectName = getSubjectName(cert);
+ Date notBeforeDate = getNotBeforeDate(cert);
+ System.out.println(Messages.getFormattedString("SFHelper.11", //$NON-NLS-1$
+ new Object[] { issuerName,
+ subjectName,
+ notBeforeDate }));
+ }
+ X500Principal issuer = cert.getIssuerX500Principal();
+ BigInteger serialNumber = cert.getSerialNumber();
+ byte[] authenticatedAttributes = null;
+ byte[] encryptedDigest = signedSFBytes;
+ byte[] unauthenticatedAttributes = null;
+ SignerInfo signerInfo = new SignerInfo(issuer,
+ serialNumber,
+ hashAlgorithmIdentifierSHA1,
+ authenticatedAttributes,
+ digestEncryptionAlgorithmOID,
+ encryptedDigest,
+ unauthenticatedAttributes);
+ signerInfos.add(signerInfo);
+
+ PKCS7SignedData dsaContents = new PKCS7SignedData(digestAlgorithms,
+ data,
+ certificates,
+ crls,
+ signerInfos);
+ dsaContents.encode(jar);
+
+ jar.flush();
+ this.state = DSA_GENERATED;
+ }
+
+ Manifest getManifest()
+ {
+ return this.manifest;
+ }
+
+ void startSigning() throws IOException
+ {
+ if (this.state != READY)
+ throw new IllegalStateException(Messages.getString("SFHelper.9")); //$NON-NLS-1$
+
+ Manifest oldManifest = jar.getManifest();
+ this.manifest = oldManifest == null ? new Manifest()
+ : new Manifest(oldManifest);
+ this.sfMainAttributes = new Attributes();
+ this.sfEntries = new HashMap<String, Attributes>();
+ util = new HashUtils();
+
+ this.state = STARTED;
+ }
+
+ /**
+ * Hashes the designated JAR entry (the file itself); adds the resulting hash
+ * as an attribute to the manifest, and computes the hash of the added (to
+ * the Manifest) two headers and add the result as an attribute of the
+ * corresponding entry in the .SF file.
+ */
+ void updateEntry(JarEntry entry) throws IOException
+ {
+ if (this.state != STARTED)
+ throw new IllegalStateException(Messages.getString("SFHelper.10")); //$NON-NLS-1$
+
+ String name = entry.getName();
+ InputStream jeis = jar.getInputStream(entry);
+ String hash = util.hashStream(jeis);
+ if (Configuration.DEBUG)
+ log.fine("Hash of " + name + " = " + hash); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Attributes mainfestAttributes = manifest.getAttributes(name);
+ if (mainfestAttributes == null)
+ {
+ mainfestAttributes = new Attributes();
+ manifest.getEntries().put(name, mainfestAttributes);
+ }
+
+ mainfestAttributes.putValue(Main.DIGEST, hash);
+
+ // hash the newly added 2-header block and add it as an attribute to .SF
+
+ String sfHash = util.hashManifestEntry(name, hash);
+ Attributes sfAttributes = sfEntries.get(name);
+ if (sfAttributes == null)
+ {
+ sfAttributes = new Attributes();
+ sfEntries.put(name, sfAttributes);
+ }
+
+ sfAttributes.putValue(Main.DIGEST, sfHash);
+ if (Configuration.DEBUG)
+ {
+ log.fine("Name: " + name); //$NON-NLS-1$
+ log.fine(Main.DIGEST + ": " + sfHash); //$NON-NLS-1$
+ log.fine(""); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @param sectionsOnly whether to compute, in addition to the files, the hash
+ * of the mainfest itself (<code>false</code>) or not (<code>true</code>).
+ */
+ void finishSigning(boolean sectionsOnly) throws IOException
+ {
+ if (state != STARTED)
+ throw new IllegalStateException(Messages.getString("SFHelper.10")); //$NON-NLS-1$
+
+ if (sectionsOnly)
+ return;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ manifest.write(baos);
+ baos.flush();
+ String manifestHash = util.hashByteArray(baos.toByteArray());
+ if (Configuration.DEBUG)
+ log.fine("Hashed Manifest " + manifestHash); //$NON-NLS-1$
+ sfMainAttributes.putValue(Main.DIGEST_MANIFEST, manifestHash);
+
+ this.state = FINISHED;
+ }
+
+ /**
+ * Given an X.509 certificate this method returns the string representation of
+ * the Issuer Distinguished Name.
+ *
+ * @param cert an X.509 certificate.
+ * @return the string representation of the Issuer's DN.
+ */
+ private String getIssuerName(X509Certificate cert)
+ {
+ X500Principal xp = cert.getIssuerX500Principal();
+ if (xp == null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
+ + ", has null Issuer. Return [unknown]"); //$NON-NLS-1$
+ return Messages.getString("SFHelper.14"); //$NON-NLS-1$
+ }
+ String result = xp.getName();
+ if (result == null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
+ + ", has an Issuer with null DN. Return [unnamed]"); //$NON-NLS-1$
+ return Messages.getString("SFHelper.17"); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ /**
+ * Given an X.509 certificate this method returns the string representation of
+ * the Subject Distinguished Name.
+ *
+ * @param cert an X.509 certificate.
+ * @return the string representation of the Subject's DN.
+ */
+ private String getSubjectName(X509Certificate cert)
+ {
+ X500Principal xp = cert.getSubjectX500Principal();
+ if (xp == null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
+ + ", has null Subject. Return [unknown]"); //$NON-NLS-1$
+ return Messages.getString("SFHelper.14"); //$NON-NLS-1$
+ }
+ String result = xp.getName();
+ if (result == null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
+ + ", has a Subject with null DN. Return [unnamed]"); //$NON-NLS-1$
+ return Messages.getString("SFHelper.17"); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ /**
+ * Given an X.509 certificate this method returns the end validity date of
+ * this certificate.
+ *
+ * @param cert an X.509 certificate.
+ * @return the date when this certificate stops being valid.
+ */
+ private Date getNotAfterDate(X509Certificate cert)
+ {
+ Date result = cert.getNotAfter();
+ if (result == null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
+ + ", has null start-validity date. Return epoch"); //$NON-NLS-1$
+ return new Date(0);
+ }
+ return result;
+ }
+
+ /**
+ * Given an X.509 certificate this method returns the start validity date of
+ * this certificate.
+ *
+ * @param cert an X.509 certificate.
+ * @return the date when this certificate starts being valid.
+ */
+ private Date getNotBeforeDate(X509Certificate cert)
+ {
+ Date result = cert.getNotBefore();
+ if (result == null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
+ + ", has null end-validity date. Return epoch"); //$NON-NLS-1$
+ return new Date(0);
+ }
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/java2xhtml/Java2xhtml.java b/libjava/classpath/tools/gnu/classpath/tools/java2xhtml/Java2xhtml.java
new file mode 100644
index 000000000..90c6d4c38
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/java2xhtml/Java2xhtml.java
@@ -0,0 +1,1354 @@
+/* gnu.classpath.tools.java2xhtml.Java2xhtml
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+/** Java2xhtml.java Version 0.9
+ * Produces an XHTML file from Java source code with syntax highlighting,
+ * includes additional options (line numbering, tab spacing, etc.)
+ * <P>
+ * NOTE: Common java naming structure is assumed
+ * Capitalize the first letter that appears in a class or interface name
+ * Use lowercase for the first letter in a method or variable name
+ * Use only uppercase letters when naming constants
+ *
+ * @version 0.9, March 2003
+ * @author Shayne Steele
+ */
+package gnu.classpath.tools.java2xhtml;
+
+import java.io.*;
+import java.util.*;
+
+public class Java2xhtml
+{
+ //--- define CSS classes for individual output elements
+
+ private static final String sourceCodeStyle = "source";
+ private static final String lineNumberStyle = "line-number even";
+ private static final String modulusLineNumberStyle = "line-number odd";
+
+ private static final String keywordStyle = "keyword";
+ private static final String methodStyle = "method member";
+ private static final String variableStyle = "variable member";
+ private static final String singleLineCommentStyle = "line comment";
+ private static final String traditionalCommentStyle = "c comment";
+ private static final String javadocCommentStyle = "javadoc comment";
+ private static final String javadocTagStyle = "javadoc tag";
+ private static final String importNameStyle = "import header type";
+ private static final String packageNameStyle = "package header type";
+ private static final String primitiveTypeStyle = "primitive type";
+ private static final String nonPrimitiveTypeStyle = "non-primitive type";
+ private static final String constructorStyle = "constructor member";
+ private static final String constantStyle = "constant member";
+ private static final String doubleQuoteStyle = "double quote";
+ private static final String singleQuoteStyle = "single quote";
+ private static final String numericLiteralStyle = "numeric literal";
+ private static final String primitiveLiteralStyle = "primitive literal";
+
+ private static final String iconStyle = "icon";
+
+
+
+ // parse the command line arguments
+ // give a decent responce for bad input
+ // call the HTMLifier on good input
+ public static void main(String args[])
+ {
+ // parse the invokation arguments
+ if (args.length < 1 || args.length > 3) // invoked program incorrectly
+ {
+ System.out.println("Java2xhtml Version 0.9 (C) 2005 Free Software Foundation");
+ System.out.println(" Produces an XHTML file of Java source" +
+ " code with syntax highlighting,");
+ System.out.println(" includes additional options " +
+ "(line numbering, tab spacing, etc.)");
+ System.out.println(" This tool is part of GNU Classpath.");
+ System.out.println(" GNU Classpath is free software; you can redistribute it and/or modify");
+ System.out.println(" it under the terms of the GNU General Public License as published by");
+ System.out.println(" the Free Software Foundation; either version 2, or (at your option)");
+ System.out.println(" any later version.");
+ System.out.println(" NOTE: Common java naming structure is " +
+ "assumed");
+ System.out.println("");
+ System.out.println("USAGE:");
+ System.out.println("java [java options] Java2xhtml " +
+ "source.java [options file] " +
+ "[output file]");
+ System.out.println("");
+ System.out.println(" - java is the name of the Java interpreter");
+ System.out.println(" - [java options] are the optional options " +
+ "of the Java interpreter");
+ System.out.println(" - Java2xhtml is the name of this " +
+ "application");
+ System.out.println(" - source is a file or the directory to the " +
+ "Java source file(s)");
+ System.out.println(" - [options file] is the optional " +
+ "path of a file with");
+ System.out.println(" a structure like this:");
+ System.out.println(" externalStyleSheetName=file_name" +
+ " (default style.css)");
+ System.out.println(" tabSize=integer (default value is 4)");
+ System.out.println(" extraIndentation=integer " +
+ "(default value is 0)");
+ System.out.println(" lineModulus=integer (default value 5)");
+ System.out.println(" isCodeSnippet=boolean" +
+ " (default false)");
+ System.out.println(" isXHTML_1_1=boolean" +
+ " (default true)");
+ System.out.println(" hasInternalStyleSheet=boolean" +
+ " (default true)");
+ System.out.println(" hasExternalStyleSheet=boolean" +
+ " (default true)");
+ System.out.println(" hasTitle=boolean" +
+ " (default false)");
+ System.out.println(" hasLegend=boolean" +
+ " (default false)");
+ System.out.println(" hasAllBoldSourceCode=boolean" +
+ " (default false)");
+ System.out.println(" hasLineNumbers=boolean" +
+ " (default false)");
+ System.out.println(" hasLineModulusDrawnLines=boolean" +
+ " (default false)");
+ System.out.println(" hasLineModulusCodeBlocks=boolean" +
+ " (default false)");
+ System.out.println(" hasFooter=boolean" +
+ " (default false)");
+ System.out.println(" hasFooterIcons=boolean" +
+ " (default false)");
+ System.out.println(" hasFooterDate=boolean" +
+ " (default true)");
+ System.out.println(" NOTE: filename must end with '.prop'");
+ System.out.println(" Default [options file] is " +
+ "options.prop");
+ System.out.println(" - [output file] is name of the XHTML file " +
+ "that is produced");
+ System.out.println(" Default [output file] is source_java.html");
+ System.out.println("");
+ System.out.println("Output: source.java --> [output file]");
+ System.out.println(" Default Output is ");
+ System.out.println(" source.java --> source_java.html");
+ System.out.println("");
+ System.out.println("Examples of calling the program:");
+ System.out.println(" process one file (say Java2xhtml.java):");
+ System.out.println(" java Java2xhtml Java2xhtml.java");
+ System.out.println(" process one directory (say C:\\HOME):");
+ System.out.println(" java Java2xhtml C:\\HOME");
+ System.out.println(" process one directory (say C:\\HOME with a " +
+ "given options file (options.prop)):");
+ System.out.println(" java Java2xhtml C:\\HOME options.prop");
+ }
+ else
+ {
+ // invoked program correctly, now get command line arguments
+ // get the source file name
+ String sourceName;
+ sourceName = args[0];
+ // make sure that the source file exist and if so HTMLify it
+ File sourceFilePath = new File(sourceName);
+ if (sourceFilePath.exists())
+ {
+ // good pathname so HTMLify it
+ // get the default html options file name
+ String propertiesFileName = "options.prop";
+ // create a unique default html file name,
+ // bubba.java -> bubba_java.html
+ String htmlFileName = sourceName.replace('.', '_') + ".html";
+ if (args.length == 2 || args.length == 3)
+ {
+ if (args[1].endsWith(".prop"))
+ {
+ // get the user supplied html options file name
+ propertiesFileName = args[1];
+ }
+ else
+ {
+ // get the user supplied html outputfile name
+ htmlFileName = args[1];
+ }
+ }
+ if (args.length == 3)
+ {
+ if (args[2].endsWith(".prop"))
+ {
+ // get the user supplied html options file name
+ propertiesFileName = args[2];
+ }
+ else
+ {
+ // get the user supplied html outputfile name
+ htmlFileName = args[2];
+ }
+ }
+ new Java2xhtml(propertiesFileName, sourceFilePath,
+ htmlFileName);
+ }
+ else // source file does not exist, print message and exit normally
+ {
+ System.out.println("The source parameter must be an existent" +
+ " file or directory");
+ System.out.println("Run Java2xHtml without parameters for " +
+ "help");
+ }
+ }
+ }
+
+ // collect various sets of keywords
+ static Collection keywordCollection;
+ static Collection primitiveTypeCollection;
+ static Collection primitiveLiteralCollection;
+ static Collection javadocTagCollection;
+
+ // all these variables are changeable by a options file
+ int extraIndentation = 0;
+ int tabSize = 4;
+ int lineModulus = 5;
+ boolean hasLegend = false;
+ boolean hasLineNumbers = false;
+ boolean hasLineModulusDrawnLines = false;
+ boolean hasLineModulusCodeBlocks = false;
+ boolean hasFooter = false;
+ boolean hasFooterIcons = false;
+ boolean hasFooterDate = true;
+ boolean isCodeSnippet = false;
+ boolean isXHTML_1_1 = true;
+ boolean hasTitle = false;
+ boolean hasAllBoldSourceCode = false;
+ boolean hasInternalStyleSheet = true;
+ boolean hasExternalStyleSheet = true;
+ String externalStyleSheetName = "style.css";
+
+ static
+ {
+ // collection type is Hashset for unique elements and fast retieval
+ String keywordArray[] =
+ {
+ "abstract", "default", "if", "private",
+ "do", "implements", "protected", "throws",
+ "break", "import", "public", "transient",
+ "else", "instanceof", "return", "try",
+ "case", "extends", "throw", "static",
+ "catch", "final", "interface", "while",
+ "volatile", "finally", "super", "synchronized",
+ "class", "native", "switch", "package",
+ "const", "for", "new", "goto",
+ "continue", "this", "assert", "strictfp"
+ };
+ keywordCollection = new HashSet(Arrays.asList(keywordArray));
+ String primitiveTypeArray[] =
+ {
+ "boolean", "char", "byte", "short", "int",
+ "long", "float", "double", "void"
+ };
+ primitiveTypeCollection =
+ new HashSet(Arrays.asList(primitiveTypeArray));
+ String primitiveLiteralArray[]=
+ {
+ "false", "null", "true"
+ };
+ primitiveLiteralCollection =
+ new HashSet(Arrays.asList(primitiveLiteralArray));
+ String javadocTagArray[]=
+ {
+ "see", "author", "version", "param", "return", "exception",
+ "deprecated", "throws", "link", "since", "serial",
+ "serialField","serialData", "beaninfo"
+ };
+ javadocTagCollection = new HashSet(Arrays.asList(javadocTagArray));
+ }
+
+ public Java2xhtml()
+ {
+ }
+
+ // create the various keyword collections
+ // parse the html options file
+ Java2xhtml(String propertiesFileName, File sourceFilePath,
+ String htmlFileName)
+ {
+ // get html properties (use defaults if necessary)
+ File propertiesFilePath = new File (propertiesFileName);
+ if (propertiesFilePath.exists())
+ {
+ // html properies file exist try parsing it
+ try
+ {
+ InputStream propertiesFile =
+ new FileInputStream(propertiesFileName);
+ Properties htmlProperties = new Properties();
+ htmlProperties.load(propertiesFile);
+ propertiesFile.close();
+ setProperties(htmlProperties);
+ }
+ catch (IOException exception)
+ {
+ System.out.println(exception);
+ }
+ }
+ if (sourceFilePath.isFile())
+ {
+ // process the file
+ processFile(sourceFilePath, htmlFileName);
+ }
+ else if (sourceFilePath.isDirectory())
+ {
+ // process a directory
+ File [] sourceFilePathArray = sourceFilePath.listFiles();
+ for (int i = 0; i < sourceFilePathArray.length; i++)
+ {
+ if (((sourceFilePathArray[i]).getName()).endsWith(".java"))
+ {
+ // process each file that ends in .java
+ // create a unique default html file name,
+ // bubba.java -> bubba_java.html
+ htmlFileName = ((sourceFilePathArray[i]).getName()).replace(
+ '.', '_') + ".html";
+ processFile(sourceFilePathArray[i], htmlFileName);
+ }
+ }
+ }
+ }
+
+ public void setProperties(Properties htmlProperties)
+ {
+ hasLegend
+ = Boolean.valueOf(htmlProperties.getProperty("hasLegend",
+ "false")).booleanValue();
+ extraIndentation
+ = Integer.parseInt(htmlProperties.getProperty("extraIndentation", "0"));
+ tabSize
+ = Integer.parseInt(htmlProperties.getProperty("tabSize", "4"));
+ hasLineNumbers
+ = Boolean.valueOf(htmlProperties.getProperty("hasLineNumbers",
+ "false")).booleanValue();
+ lineModulus
+ = Integer.parseInt(htmlProperties.getProperty("lineModulus", "5"));
+ hasLineModulusDrawnLines
+ = Boolean.valueOf(htmlProperties.getProperty("hasLineModulusDrawnLines",
+ "false")).booleanValue();
+ hasLineModulusCodeBlocks
+ = Boolean.valueOf(htmlProperties.getProperty("hasLineModulusCodeBlocks",
+ "false")).booleanValue();
+ hasFooter
+ = Boolean.valueOf(htmlProperties.getProperty("hasFooter",
+ "false")).booleanValue();
+ hasFooterIcons
+ = Boolean.valueOf(htmlProperties.getProperty("hasFooterIcons",
+ "false")).booleanValue();
+ hasFooterDate
+ = Boolean.valueOf(htmlProperties.getProperty("hasFooterDate",
+ "true")).booleanValue();
+ isXHTML_1_1
+ = Boolean.valueOf(htmlProperties.getProperty("isXHTML_1_1",
+ "true")).booleanValue();
+ isCodeSnippet
+ = Boolean.valueOf(htmlProperties.getProperty("isCodeSnippet",
+ "false")).booleanValue();
+ hasTitle
+ = Boolean.valueOf(htmlProperties.getProperty("hasTitle",
+ "false")).booleanValue();
+ hasAllBoldSourceCode
+ = Boolean.valueOf(htmlProperties.getProperty("hasAllBoldSourceCode",
+ "false")).booleanValue();
+ hasInternalStyleSheet
+ = Boolean.valueOf(htmlProperties.getProperty("hasInternalStyleSheet",
+ "true")).booleanValue();
+ hasExternalStyleSheet
+ = Boolean.valueOf(htmlProperties.getProperty("hasExternalStyleSheet",
+ "true")).booleanValue();
+ externalStyleSheetName
+ = htmlProperties.getProperty("externalStyleSheetName", "style.css");
+ }
+
+
+ // read the file and put it into a stringbuffer
+ void processFile(File sourceFilePath, String htmlFileName)
+ {
+ // open the file, copy it to a Stringbuffer , process into an
+ // HTMLified String and convert result into an HTML file
+ try
+ {
+ BufferedReader sourceReader =
+ new BufferedReader(new FileReader(sourceFilePath));
+ StringBuffer bufferIn = new StringBuffer();
+ int readInInt = 0;
+ char presentChar = 0;
+ // copy file into a Stringbuffer
+ while (readInInt != -1) // -1 value means end of stream/file
+ {
+ // put the file into a Stringbuffer
+ readInInt= sourceReader.read();
+ presentChar = ((readInInt >= 0) ? (char) readInInt : 0);
+ bufferIn.append(presentChar);
+ }
+ sourceReader.close();
+ BufferedWriter tempBufferedWriter =
+ new BufferedWriter(new FileWriter(htmlFileName));
+ tempBufferedWriter.write(makeHTML(bufferIn,
+ sourceFilePath.getName()));
+ tempBufferedWriter.close();
+ System.out.println(sourceFilePath.getName() + " --> " +
+ htmlFileName);
+ }
+ catch (IOException exception)
+ {
+ System.out.println(exception);
+ }
+ }
+
+ // constant 'States' java source code can be in
+ public final static class State
+ {
+ public final static State TEXT = new State();
+ public final static State IMPORT_NAME = new State();
+ public final static State PARAM_VARIABLE = new State();
+ public final static State JAVADOC = new State();
+ public final static State PACKAGE_NAME = new State();
+ public final static State DOUBLE_QUOTE = new State();
+ public final static State SINGLE_QUOTE = new State();
+ public final static State TRADITIONAL_COMMENT = new State();
+ public final static State LINE_COMMENT = new State();
+
+ // empty constructor
+ private State()
+ {
+ // empty body
+ }
+ }
+
+ // Convert java source code StringBufffer into colorized (and tab spaced)
+ // HTML String .
+ // Assumes that Java naming convention is used
+ // Uses a very basic state machine design.
+ public String makeHTML(StringBuffer bufferIn, String sourceFileName)
+ {
+ int codeLineNumber = 0;
+ boolean isNewLine = true;
+ boolean isNewBlock = true;
+ int identifierLength = 0;
+ int qualifiedIdentifierLength = 0;
+ int presentIndex = -1;
+ int spaceLength = 0;
+ int saveIndex = 0;
+ char presentChar = 0;
+ State presentState = State.TEXT;
+ StringBuffer bufferOut = new StringBuffer(8192);
+ if (!isCodeSnippet)
+ {
+ bufferOut.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
+ if (isXHTML_1_1)
+ {
+ bufferOut.append("<!DOCTYPE html PUBLIC " +
+ "\"-//W3C//DTD XHTML 1.1//EN\"\r\n");
+ bufferOut.append(" \"http://www.w3.org/TR/xhtml11/DTD/" +
+ "xhtml11.dtd\">\r\n");
+ bufferOut.append("<html xmlns=\"http://www.w3.org/1999/xhtml\""+
+ " xml:lang=\"en\">\r\n");
+ }
+ else
+ {
+ bufferOut.append("<!DOCTYPE html PUBLIC " +
+ "\"-//W3C//DTD XHTML 1.0 Strict//EN\"\r\n");
+ bufferOut.append(" \"http://www.w3.org/TR/xhtml1/DTD/" +
+ "xhtml1-strict.dtd\">\r\n");
+ bufferOut.append("<html xmlns=\"http://www.w3.org/1999/xhtml\""+
+ " xml:lang=\"en\" lang=\"en\">\r\n");
+ }
+ bufferOut.append(" <head>\r\n");
+ bufferOut.append(" <title>\r\n");
+ bufferOut.append(" " + sourceFileName + "\r\n");
+ bufferOut.append(" </title>\r\n");
+ bufferOut.append(" <meta name=\"generator\"\r\n");
+ bufferOut.append(" content=\"Java2xhtml 0.9\" />\r\n");
+ if (hasInternalStyleSheet)
+ {
+ bufferOut.append(" <style type=\"text/css\">\r\n");
+ bufferOut.append(" <!-- /* <![CDATA[ */\r\n");
+ bufferOut.append(" ." + sourceCodeStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #000000;\r\n");
+ bufferOut.append(" background-color: #FFFFFF;\r\n");
+ if (hasAllBoldSourceCode)
+ {
+ bufferOut.append(" font-weight: bold;\r\n");
+ }
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + lineNumberStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" font-weight: normal;\r\n");
+ bufferOut.append(" color: #000000;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ if (lineModulus > 0)
+ {
+ bufferOut.append(" ." + modulusLineNumberStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" font-weight: bold;\r\n");
+ bufferOut.append(" color: #000000;\r\n");
+ bufferOut.append(" background-color: ");
+ bufferOut.append("transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ if (hasLineModulusDrawnLines)
+ {
+ bufferOut.append(" .modulusLineStyle\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" text-decoration: ");
+ bufferOut.append("line-through;\r\n");
+ bufferOut.append(" color: #000000;\r\n");
+ bufferOut.append(" background-color: ");
+ bufferOut.append("transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ }
+ if (hasLineModulusCodeBlocks)
+ {
+ bufferOut.append(" .modulusBlockPREStyle\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" margin: 0em\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" .modulusBlockStyle\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #000000;\r\n");
+ bufferOut.append(" background-color: ");
+ bufferOut.append("#CCCCCC;\r\n");
+ bufferOut.append(" }\r\n");
+ }
+ }
+ bufferOut.append(" ." + keywordStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #9900FF;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + methodStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #0000FF;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + variableStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #CC9933;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + singleLineCommentStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #CC3333;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + traditionalCommentStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #FF0000;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + javadocCommentStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #CC0033;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + javadocTagStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #0099CC;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + importNameStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #33CCCC;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + packageNameStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #339999;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + primitiveTypeStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #009900;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + nonPrimitiveTypeStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #009966;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + constructorStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #3300CC;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + constantStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #666666;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + doubleQuoteStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #996633;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" font-style: italic;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + singleQuoteStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #663333;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" font-style: oblique;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + numericLiteralStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #333300;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" ." + primitiveLiteralStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" color: #006600;\r\n");
+ bufferOut.append(" background-color: transparent;\r\n");
+ bufferOut.append(" }\r\n");
+ if (hasFooterIcons)
+ {
+ bufferOut.append(" ." + iconStyle + "\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" border-style: none;\r\n");
+ bufferOut.append(" }\r\n");
+ }
+ if (hasTitle)
+ {
+ bufferOut.append(" #title\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" text-align: center;\r\n");
+ bufferOut.append(" font-size: xx-large;\r\n");
+ bufferOut.append(" }\r\n");
+ }
+ if (hasLegend)
+ {
+ bufferOut.append(" #legendTitle\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" text-align: center;\r\n");
+ bufferOut.append(" font-size: x-large;\r\n");
+ bufferOut.append(" }\r\n");
+ bufferOut.append(" #legend\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" font-family: monospace;\r\n");
+ bufferOut.append(" font-size: large;\r\n");
+ bufferOut.append(" }\r\n");
+ }
+ if (hasFooter)
+ {
+ bufferOut.append(" #footer\r\n");
+ bufferOut.append(" {\r\n");
+ bufferOut.append(" font-size: xx-small;\r\n");
+ bufferOut.append(" }\r\n");
+ }
+ bufferOut.append(" /* ]]> */ -->\r\n");
+ bufferOut.append(" </style>\r\n");
+ }
+
+ if (hasExternalStyleSheet)
+ {
+ bufferOut.append(" <link rel=\"stylesheet\" " +
+ "type=\"text/css\" href=\"" +
+ externalStyleSheetName + "\" />\r\n");
+ }
+ bufferOut.append(" </head>\r\n");
+ bufferOut.append(" <body>\r\n");
+ }
+ if (hasTitle)
+ {
+ bufferOut.append(" <div id=\"title\">\r\n");
+ bufferOut.append(" " + sourceFileName + "\r\n");
+ bufferOut.append(" </div>\r\n");
+ bufferOut.append(" <hr />\r\n");
+ }
+ if (hasLegend)
+ {
+ bufferOut.append(" <div id=\"legendTitle\">\r\n");
+ bufferOut.append(" Legend\r\n");
+ bufferOut.append(" </div>\r\n");
+ bufferOut.append(" <div class=\"" + sourceCodeStyle + "\">\r\n");
+ bufferOut.append(" <div id=\"legend\">\r\n");
+ bufferOut.append(" <span class=\"" + keywordStyle + "\">");
+ bufferOut.append("keyword</span>\r\n");
+ bufferOut.append(" <span class=\"" + methodStyle + "\">");
+ bufferOut.append("method</span>\r\n");
+ bufferOut.append(" <span class=\"" + variableStyle + "\">variable" +
+ "</span>\r\n");
+ bufferOut.append(" <span class=\"" + singleLineCommentStyle + "\">" +
+ "singleLineComment</span>\r\n");
+ bufferOut.append(" <span class=\"" + traditionalCommentStyle + "\">" +
+ "traditionalComment</span>\r\n");
+ bufferOut.append(" <span class=\"" + javadocCommentStyle + "\">" +
+ "javadocComment</span>\r\n");
+ bufferOut.append(" <span class=\"" + javadocTagStyle + "\">javadocTag" +
+ "</span>\r\n");
+ bufferOut.append(" <span class=\"" + importNameStyle + "\">" +
+ "importName</span>\r\n");
+ bufferOut.append(" <span class=\"" + packageNameStyle + "\">" +
+ "packageName</span>\r\n");
+ bufferOut.append(" <span class=\"" + primitiveTypeStyle + "\">" +
+ "primitiveType</span>\r\n");
+ bufferOut.append(" <span class=\"" + nonPrimitiveTypeStyle + "\">" +
+ "nonPrimitiveType</span>\r\n");
+ bufferOut.append(" <span class=\"" + constructorStyle + "\">" +
+ "constructor</span>\r\n");
+ bufferOut.append(" <span class=\"" + constantStyle + "\">" +
+ "constant</span>\r\n");
+ bufferOut.append(" <span class=\"" + doubleQuoteStyle + "\">" +
+ "doubleQuote</span>\r\n");
+ bufferOut.append(" <span class=\"" + singleQuoteStyle + "\">" +
+ "singleQuote</span>\r\n");
+ bufferOut.append(" <span class=\"" + numericLiteralStyle + "\">" +
+ "numericLiteral</span>\r\n");
+ bufferOut.append(" <span class=\"" + primitiveLiteralStyle + "\">" +
+ "primitiveLiteral</span>\r\n");
+ bufferOut.append(" </div>\r\n");
+ bufferOut.append(" </div>\r\n");
+ bufferOut.append(" <hr />\r\n");
+ }
+ bufferOut.append(" <div class=\"" + sourceCodeStyle + "\">\r\n");
+ if (hasLineModulusCodeBlocks)
+ {
+ bufferOut.append("<pre class=\"modulusBlockPREStyle\">\r\n");
+ }
+ else
+ {
+ bufferOut.append("<pre>\r\n");
+ }
+ // process the input Java code Stringbuffer
+ // subtract 2 from the bufferIn.length() to get EOF marker
+ while (presentIndex++ < (bufferIn.length() - 2))
+ {
+ for (int i = 0; i < extraIndentation; i++)
+ {
+ bufferOut.append(" ");
+ }
+ if ((hasLineNumbers || hasLineModulusCodeBlocks) && isNewLine)
+ {
+ // add line numbers if desired
+ // line numbers are 1 - 9999 then rotate line numbers
+ codeLineNumber = (++codeLineNumber)%10000;
+ if ((lineModulus > 0) && hasLineModulusCodeBlocks &&
+ (codeLineNumber%lineModulus == 1))
+ {
+ if (isNewBlock)
+ {
+ if ((State.TRADITIONAL_COMMENT == presentState) ||
+ (State.JAVADOC == presentState))
+ {
+ bufferOut.insert((bufferOut.length() -
+ ("\r\n").length()),
+ "</span>");
+ }
+ bufferOut.append("</pre>\r\n");
+ bufferOut.append(" <div class=");
+ bufferOut.append("\"modulusBlockStyle\">");
+ bufferOut.append("\r\n<pre class=\"");
+ bufferOut.append("modulusBlockPREStyle\">\r\n");
+ if (State.TRADITIONAL_COMMENT == presentState)
+ {
+ bufferOut.append("<span class=" +
+ "\"" + traditionalCommentStyle + "\">");
+ }
+ if (State.JAVADOC == presentState)
+ {
+ bufferOut.append("<span class=" +
+ "\"" + javadocCommentStyle + "\">");
+ }
+ }
+ isNewBlock = !isNewBlock;
+ }
+ // make straight columns of line numbers
+ if (codeLineNumber < 1000)
+ {
+ bufferOut.append(" ");
+ }
+ if (codeLineNumber < 100)
+ {
+ bufferOut.append(" ");
+ }
+ if (codeLineNumber < 10)
+ {
+ bufferOut.append(" ");
+ }
+ bufferOut.append("<a name=\"line.");
+ bufferOut.append(codeLineNumber);
+ bufferOut.append("\">");
+
+ if (hasLineNumbers)
+ {
+ if ((lineModulus > 0) && (codeLineNumber%lineModulus == 0))
+ {
+ bufferOut.append("<span class=" +
+ "\"" + modulusLineNumberStyle + "\">");
+ bufferOut.append(codeLineNumber);
+ bufferOut.append(": </span>");
+ if (hasLineModulusDrawnLines)
+ {
+ // compute spaceLength so a line can be drawn
+ while ((presentIndex != (bufferIn.length() - 1)) &&
+ ((Character.isSpaceChar(
+ bufferIn.charAt(presentIndex))) ||
+ (bufferIn.charAt(presentIndex) == '\t')))
+ {
+ // for each tab, insert tabSize spaces
+ if (bufferIn.charAt(presentIndex) == '\t')
+ {
+ for (int i = 0; i < tabSize; i++)
+ {
+ bufferIn.insert(presentIndex + 1, " ");
+ }
+ presentIndex++;
+ continue;
+ }
+ if (' ' == bufferIn.charAt(presentIndex))
+ {
+ // read a space so place a space
+ bufferOut.append(" ");
+ spaceLength += (" ").length();
+ }
+ else
+ {
+ // a white space character was read
+ bufferOut.append(bufferIn.charAt(
+ presentIndex));
+ ++spaceLength;
+ }
+ presentIndex++;
+ }
+ // check if line is empty
+ // (no printable characters on line)
+ if ((presentIndex == (bufferIn.length() - 1)) ||
+ (Character.isWhitespace(bufferIn.charAt(
+ presentIndex))))
+ {
+ spaceLength = 0;
+ }
+ // draw the line
+ if (spaceLength > 1)
+ {
+ bufferOut.insert((bufferOut.length() -
+ spaceLength), "<span class=" +
+ "\"modulusLineStyle\">");
+ bufferOut.insert((bufferOut.length() -
+ (" ").length()), "</span>");
+ }
+ spaceLength = 0;
+ }
+ }
+ else
+ {
+ // line numbers are in lineNumberColor
+ bufferOut.append("<span class=\"" + lineNumberStyle + "\">");
+ bufferOut.append(codeLineNumber);
+ bufferOut.append(":</span> ");
+ }
+ }
+ isNewLine = false;
+
+ bufferOut.append("</a>");
+ }
+ // a state machine
+ presentChar = bufferIn.charAt(presentIndex);
+ if ((Character.isJavaIdentifierPart(presentChar)) ||
+ ((State.IMPORT_NAME == presentState) && (presentChar == '*')))
+ {
+ // this is an identifier
+ bufferOut.append(presentChar);
+ identifierLength++;
+ continue; // keep adding characters until identifier is done
+ }
+ if (identifierLength > 0)
+ {
+ // identifier
+ qualifiedIdentifierLength =
+ qualifiedIdentifierLength + identifierLength;
+ if (bufferIn.charAt(presentIndex) == '.')
+ {
+ // qualified identifier
+ bufferOut.append(presentChar);
+ qualifiedIdentifierLength++;
+ identifierLength = 0;
+ continue; // keep adding characters to qualified identifier
+ }
+ String identifier =
+ bufferOut.substring(bufferOut.length() -
+ identifierLength);
+ if ((State.PARAM_VARIABLE == presentState))
+ {
+ // any identifier after a param in a javadoc is assumed to
+ // be a variable
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + variableStyle + "\">");
+ bufferOut.append("</span>");
+ presentState = State.JAVADOC;
+ }
+ else if (State.JAVADOC == presentState)
+ {
+ // in javadoc state
+ if ((javadocTagCollection.contains(identifier)) &&
+ (bufferIn.charAt(presentIndex -
+ (identifierLength + 1)) == '@'))
+ {
+ // identifier is a javadocTag
+ bufferOut.insert(bufferOut.length() - identifierLength,
+ "<span class=\"" + javadocTagStyle + "\">");
+ bufferOut.append("</span>");
+ if (("param").equals(identifier))
+ {
+ // any identifier after a param is assumed to
+ // be a variable, get into a state to do this
+ presentState = State.PARAM_VARIABLE;
+ }
+ }
+ }
+ else if (State.IMPORT_NAME == presentState)
+ {
+ // import identifier
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + importNameStyle + "\">");
+ bufferOut.append("</span>");
+ presentState = State.TEXT;
+ }
+ else if (State.PACKAGE_NAME == presentState)
+ {
+ // package identifier
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + packageNameStyle + "\">");
+ bufferOut.append("</span>");
+ presentState = State.TEXT;
+ }
+ else if (State.TEXT == presentState)
+ {
+ if (keywordCollection.contains(identifier))
+ {
+ // identifier is a keyword
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + keywordStyle + "\">");
+ bufferOut.append("</span>");
+ if (("import").equals(identifier))
+ {
+ // anything after an import in text mode must be
+ // an import name, so enter state to process this
+ presentState = State.IMPORT_NAME;
+ }
+ else if (("package").equals(identifier))
+ {
+ // anything after an package in text mode must be
+ // an package name, so enter state to process this
+ presentState = State.PACKAGE_NAME;
+ }
+ }
+ else if (primitiveTypeCollection.contains(identifier))
+ {
+ // identifier is a primitive type
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + primitiveTypeStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ else if ((identifier.equals(identifier.toUpperCase())) &&
+ (!(Character.isDigit(identifier.charAt(0)))))
+ {
+ // identifier is a constant
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + constantStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ else if (Character.isUpperCase(identifier.charAt(0)))
+ {
+ // identifier is a constructor or non-primitive type
+ // eat white space
+ saveIndex = presentIndex;
+ while (Character.isWhitespace(
+ bufferIn.charAt(saveIndex++)))
+ {
+ //empty body
+ }
+ if (bufferIn.charAt(--saveIndex) == '(')
+ { // identifier is a constructor
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=" +
+ "\"" + constructorStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ else
+ {
+ // identifier is a non-primitive type
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=" +
+ "\"" + nonPrimitiveTypeStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ }
+ else if (!(Character.isDigit(identifier.charAt(0)) ||
+ primitiveLiteralCollection.contains(identifier)))
+ {
+ // identifier is a method or a variable
+ // eat white space
+ saveIndex = presentIndex;
+ while (Character.isWhitespace(
+ bufferIn.charAt(saveIndex++)))
+ {
+ // empty body
+ }
+ --saveIndex;
+ // identifier is a method
+ if (bufferIn.charAt(saveIndex) == '(')
+ {
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + methodStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ else if (bufferIn.charAt(saveIndex) == ',')
+ {
+ // comma seperated variables
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + variableStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ else
+ {
+ // a variable
+ // take care of cases such as array[index].variable
+ if (bufferIn.charAt(presentIndex -
+ (qualifiedIdentifierLength
+ + 1)) == '.')
+ {
+ qualifiedIdentifierLength++;
+ }
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=\"" + variableStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ }
+ else
+ {
+ if (primitiveLiteralCollection.contains(identifier))
+ {
+ // primitiveLiteral (boolean or null)
+ bufferOut.insert(bufferOut.length() -
+ identifierLength, "<span class=" +
+ "\"" + primitiveLiteralStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ // a numeric literal
+ else
+ {
+ if (((presentIndex -
+ (qualifiedIdentifierLength + 1)) > 0) &&
+ (bufferIn.charAt(presentIndex -
+ (qualifiedIdentifierLength + 1)) == '.'))
+ {
+ qualifiedIdentifierLength++;
+ }
+ bufferOut.insert(bufferOut.length() -
+ qualifiedIdentifierLength,
+ "<span class=" +
+ "\"" + numericLiteralStyle + "\">");
+ bufferOut.append("</span>");
+ }
+ }
+ }
+ qualifiedIdentifierLength = 0;
+ identifierLength = 0;
+ }
+ // process characters NOT in identifiers
+ switch (presentChar)
+ {
+ case '&': //ampersand
+ bufferOut.append("&amp;"); // HTMLify character
+ break;
+ case '<': // less than sign
+ bufferOut.append("&lt;"); // HTMLify character
+ break;
+ case '>': // greater than sign
+ bufferOut.append("&gt;"); // HTMLify character
+ break;
+ case '\"': // double quote
+ bufferOut.append("&quot;"); // HTMLify character
+ if (State.TEXT == presentState)
+ {
+ presentState = State.DOUBLE_QUOTE;
+ bufferOut.insert(bufferOut.length()-("&quot;").length(),
+ "<span class=\"" + doubleQuoteStyle + "\">");
+ }
+ else if (State.DOUBLE_QUOTE == presentState)
+ {
+ presentState = State.TEXT;
+ bufferOut.append("</span>");
+ }
+ break;
+ case '\'': // single quote
+ bufferOut.append("\'");
+ if (State.TEXT == presentState)
+ {
+ presentState = State.SINGLE_QUOTE;
+ bufferOut.insert(bufferOut.length() - ("\'").length(),
+ "<span class=\"" + singleQuoteStyle + "\">");
+ }
+ else if (State.SINGLE_QUOTE == presentState)
+ {
+ presentState = State.TEXT;
+ bufferOut.append("</span>");
+ }
+ break;
+ case '\\': // backslash
+ bufferOut.append("\\");
+ if ((State.DOUBLE_QUOTE == presentState) ||
+ (State.SINGLE_QUOTE == presentState))
+ {
+ // treat as a character escape sequence
+ bufferOut.append(bufferIn.charAt(++presentIndex));
+ }
+ break;
+ case '\t': // tab
+ // replace tabs with tabsize number of spaces
+ for (int i = 0; i < tabSize; i++)
+ {
+ bufferOut.append(' ');
+ }
+ break;
+ case '*': // star
+ bufferOut.append("*");
+ if ((State.TEXT == presentState) &&
+ (bufferIn.charAt(presentIndex - 1) == '/'))
+ {
+ if (((bufferIn.length() - 1) > presentIndex) &&
+ (bufferIn.charAt(presentIndex + 1) == '*'))
+ {
+ presentState = State.JAVADOC;
+ bufferOut.insert(bufferOut.length() -
+ ("/*").length(), "<span class=" +
+ "\"" + javadocCommentStyle + "\">");
+ }
+ else
+ {
+ presentState = State.TRADITIONAL_COMMENT;
+ bufferOut.insert(bufferOut.length() -
+ ("/*").length(), "<span class=" +
+ "\"" + traditionalCommentStyle + "\">");
+ }
+ }
+ break;
+ case '/': // foward slash
+ bufferOut.append("/");
+ if (((State.TRADITIONAL_COMMENT == presentState) ||
+ (State.JAVADOC == presentState)) &&
+ (bufferIn.charAt(presentIndex - 1) == '*'))
+ {
+ bufferOut.append("</span>");
+ presentState = State.TEXT;
+ }
+ if ((State.TEXT == presentState) &&
+ (presentIndex > 0) &&
+ (bufferIn.charAt(presentIndex - 1) == '/'))
+ {
+ bufferOut.insert(bufferOut.length() - ("//").length(),
+ "<span class=" +
+ "\"" + singleLineCommentStyle + "\">");
+ presentState = State.LINE_COMMENT;
+ }
+ break;
+ case '\r': // carriage return
+ // fall through
+ case '\n': // line feed
+ // all HTML lines end in \r\n
+ if ((bufferIn.charAt(presentIndex) == '\r') &&
+ ((bufferIn.length() - 1) > presentIndex) &&
+ (bufferIn.charAt(presentIndex + 1) == '\n'))
+ {
+ ++presentIndex;
+ }
+ // end single line comments
+ if (State.LINE_COMMENT == presentState)
+ {
+ bufferOut.append("</span>");
+ presentState = State.TEXT;
+ }
+ // end of block
+ if ((lineModulus > 0) && hasLineModulusCodeBlocks &&
+ ((codeLineNumber%lineModulus == 0) && !isNewBlock))
+ {
+ // end multi-line spanning states
+ if ((State.TRADITIONAL_COMMENT == presentState) ||
+ (State.JAVADOC == presentState))
+ {
+ bufferOut.append("</span>");
+ }
+ bufferOut.append("\r\n");
+ bufferOut.append("</pre>\r\n");
+ bufferOut.append(" </div>\r\n");
+ bufferOut.append("<pre class=\"");
+ bufferOut.append("modulusBlockPREStyle\">\r\n");
+ // restart multi-line spanning states
+ if (State.TRADITIONAL_COMMENT == presentState)
+ {
+ bufferOut.append("<span class=" +
+ "\"" + traditionalCommentStyle + "\">");
+ }
+ if (State.JAVADOC == presentState)
+ {
+ bufferOut.append("<span class=" +
+ "\"" + javadocCommentStyle + "\">");
+ }
+ }
+ else
+ {
+ // div automatically starts new line
+ bufferOut.append("\r\n");
+ }
+ isNewLine = true;
+ break;
+ case 0: // nul character
+ if ((State.LINE_COMMENT == presentState) &&
+ (presentIndex == (bufferIn.length() - 1)))
+ {
+ bufferOut.append("</span>");
+ }
+ break;
+ default: // everything else
+ bufferOut.append(presentChar);
+ }
+ qualifiedIdentifierLength = 0;
+ }
+ if (presentState == State.LINE_COMMENT) {
+ bufferOut.append("</span>\r\n");
+ }
+
+ bufferOut.append("</pre>\r\n");
+ // end block early if no more source code
+ if ((lineModulus > 0) && hasLineModulusCodeBlocks && !isNewBlock &&
+ (codeLineNumber%lineModulus != 0))
+ {
+ bufferOut.append(" </div>\r\n");
+ }
+ bufferOut.append(" </div>\r\n"); // end div of sourceCodeStyle
+ // if code snippet then don't add ending tags of xhtml page
+ if (!isCodeSnippet)
+ {
+ // if footer mode then add a footer
+ if (hasFooter)
+ {
+ bufferOut.append(" <hr />\r\n");
+ bufferOut.append(" <div id=\"footer\">\r\n");
+ if (hasFooterIcons)
+ {
+ if (hasFooterDate)
+ {
+ bufferOut.append(" <script type=\"text/javaScript\"");
+ bufferOut.append(">\r\n");
+ bufferOut.append(" <!-- // <![CDATA[\r\n");
+ bufferOut.append(" document.write(\"Document last");
+ bufferOut.append(" modified on \"");
+ bufferOut.append(" + document.lastModified + ");
+ bufferOut.append("\"<br />\");\r\n");
+ bufferOut.append(" // ]]> -->\r\n");
+ bufferOut.append(" </script>\r\n");
+ }
+ bufferOut.append(" <a href=\"");
+ bufferOut.append("http://validator.w3.org/check/referer");
+ bufferOut.append("\">\r\n");
+ bufferOut.append(" <img class=\"" + iconStyle + "\" src=\"");
+ bufferOut.append("http://www.w3.org/Icons/");
+ if (isXHTML_1_1)
+ {
+ bufferOut.append("valid-xhtml11\"\r\n");
+ bufferOut.append(" alt=\"Valid XHTML 1.1!\"");
+ }
+ else
+ {
+ bufferOut.append("valid-xhtml10\"\r\n");
+ bufferOut.append(" alt=\"Valid XHTML 1.0!\"");
+ }
+ bufferOut.append(" height=\"31\" ");
+ bufferOut.append("width=\"88\" />\r\n");
+ bufferOut.append(" </a>\r\n");
+ bufferOut.append(" &#160;\r\n");
+ bufferOut.append(" <a href=\"");
+ bufferOut.append("http://jigsaw.w3.org");
+ bufferOut.append("/css-validator/check/referer");
+ bufferOut.append("\">\r\n");
+ bufferOut.append(" <img class=\"" + iconStyle + "\" src=\"");
+ bufferOut.append("http://jigsaw.w3.org/");
+ bufferOut.append("css-validator/images/vcss");
+ bufferOut.append("\"\r\n");
+ bufferOut.append(" alt=\"Valid CSS!\"");
+ bufferOut.append(" height=\"31\" width=\"88\" />\r\n");
+ bufferOut.append(" </a>\r\n");
+ }
+ else
+ {
+ bufferOut.append(" This is a valid\r\n");
+ bufferOut.append(" <a href=\"http://");
+ bufferOut.append("validator.w3.org/check/referer");
+ if (isXHTML_1_1)
+ {
+ bufferOut.append("\">XHTML 1.1</a>\r\n");
+ }
+ else
+ {
+ bufferOut.append("\">XHTML 1.0</a>\r\n");
+ }
+ bufferOut.append(" with\r\n");
+ bufferOut.append(" <a href=\"http://");
+ bufferOut.append("jigsaw.w3.org");
+ bufferOut.append("/css-validator/check/referer");
+ bufferOut.append("\">CSS</a>\r\n");
+ bufferOut.append(" document \r\n");
+ if (hasFooterDate)
+ {
+ bufferOut.append(" <script type=\"text/javaScript\"");
+ bufferOut.append(">\r\n");
+ bufferOut.append(" <!-- // <![CDATA[\r\n");
+ bufferOut.append(" document.write(\"last modified");
+ bufferOut.append(" on \" + document.lastModified);");
+ bufferOut.append("\r\n");
+ bufferOut.append(" // ]]> -->\r\n");
+ bufferOut.append(" </script>\r\n");
+ }
+ }
+ bufferOut.append(" </div>\r\n");
+ }
+ bufferOut.append(" </body>\r\n");
+ bufferOut.append("</html>\r\n");
+ }
+ return bufferOut.toString();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java b/libjava/classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java
new file mode 100644
index 000000000..ffecac35c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java
@@ -0,0 +1,376 @@
+/* ClassWrapper.java - wrap ASM class objects
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+public class ClassWrapper
+ extends ClassNode
+{
+ Main classpath;
+
+ ClassWrapper superClass;
+
+ ArrayList<ClassWrapper> interfaceClasses;
+
+ // The virtual table for this class.
+ ArrayList<MethodNode> vtable;
+
+ // A set of all the bridge method targets we've found.
+ HashSet<String> bridgeTargets;
+
+ // A set of all the method names in this class.
+ HashSet<String> methodNames = new HashSet<String>();
+
+ // This maps a method name + descriptor, e.g. "method()V", to the
+ // name chosen for the method. This is used when computing the
+ // names of bridge method targets.
+ HashMap<String,String> methodNameMap = new HashMap<String,String>();
+
+ public ClassWrapper(Main classpath)
+ {
+ this.classpath = classpath;
+ }
+
+ public boolean hasNativeMethod()
+ {
+ Iterator<?> i = methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode method = (MethodNode) i.next();
+ if (Modifier.isNative(method.access))
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isThrowable() throws IOException
+ {
+ linkSupers();
+ ClassWrapper self = this;
+ while (self != null)
+ {
+ if (self.name.equals("java/lang/Throwable"))
+ return true;
+ self = self.superClass;
+ }
+ return false;
+ }
+
+ void linkSupers() throws IOException
+ {
+ if (superName == null)
+ {
+ // Object, do nothing.
+ return;
+ }
+ if (superClass == null)
+ {
+ superClass = classpath.getClass(superName);
+ assert interfaceClasses == null;
+ interfaceClasses = new ArrayList<ClassWrapper>();
+ for (int i = 0; i < interfaces.size(); ++i)
+ {
+ String ifname = (String) interfaces.get(i);
+ ClassWrapper iface = classpath.getClass(ifname);
+ iface.linkSupers();
+ interfaceClasses.add(iface);
+ }
+ }
+ superClass.linkSupers();
+ }
+
+ private int findSlot(MethodNode method)
+ {
+ for (int i = vtable.size() - 1; i >= 0; --i)
+ {
+ MethodNode base = vtable.get(i);
+ if (MethodHelper.overrides(method, base))
+ return i;
+ }
+ return - 1;
+ }
+
+ private void addInterfaceMethods(ClassWrapper iface)
+ {
+ Iterator<?> i = iface.methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode im = (MethodNode) i.next();
+ int slot = findSlot(im);
+ if (slot == - 1)
+ {
+ vtable.add(im);
+ // Also add it to our local methods.
+ methods.add(im);
+ }
+ }
+ addInterfaces(iface);
+ }
+
+ private void addInterfaces(ClassWrapper base)
+ {
+ if (base.interfaceClasses == null)
+ return;
+ Iterator<?> i = base.interfaceClasses.iterator();
+ while (i.hasNext())
+ {
+ ClassWrapper iface = (ClassWrapper) i.next();
+ addInterfaceMethods(iface);
+ }
+ }
+
+ private void addLocalMethods()
+ {
+ Iterator<?> i = methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode meth = (MethodNode) i.next();
+ methodNames.add(meth.name);
+ if (Modifier.isStatic(meth.access))
+ continue;
+ int slot = findSlot(meth);
+ if (slot == - 1)
+ vtable.add(meth);
+ else
+ vtable.set(slot, meth);
+ }
+ }
+
+ private void makeVtable() throws IOException
+ {
+ if (vtable != null)
+ return;
+ if (superClass != null)
+ {
+ superClass.makeVtable();
+ vtable = new ArrayList<MethodNode>(superClass.vtable);
+ bridgeTargets = new HashSet<String>(superClass.bridgeTargets);
+ methodNameMap = new HashMap<String,String>(superClass.methodNameMap);
+ }
+ else
+ {
+ // Object.
+ vtable = new ArrayList<MethodNode>();
+ bridgeTargets = new HashSet<String>();
+ methodNameMap = new HashMap<String,String>();
+ }
+ addLocalMethods();
+ addInterfaces(this);
+
+ // Make a set of all the targets of bridge methods. We rename
+ // bridge target methods to avoid problems with C++. You might
+ // think we could rename the bridge methods themselves, but bridge
+ // methods by definition override a method from the superclass --
+ // and we have to consider the superclass' header as an
+ // unchangeable entity.
+ Iterator<?> i = methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode m = (MethodNode) i.next();
+ String desc = MethodHelper.getBridgeTarget(m);
+ if (desc != null)
+ {
+ String sum = m.name + desc;
+ boolean newTarget = bridgeTargets.add(sum);
+ if (newTarget)
+ {
+ // Bridge target that is new in this class.
+ String cname = this.name;
+ int index = cname.lastIndexOf('/');
+ cname = cname.substring(index + 1);
+ methodNameMap.put(sum, cname + "$" + m.name);
+ }
+ }
+ }
+ }
+
+ private void printFields(CniPrintStream out)
+ {
+ Iterator<?> i = fields.iterator();
+ ClassWrapper self = superClass;
+ while (i.hasNext())
+ {
+ FieldNode f = (FieldNode) i.next();
+ boolean hasMethodName = methodNames.contains(f.name);
+ if (FieldHelper.print(out, f, self, hasMethodName))
+ self = null;
+ }
+ }
+
+ private void printMethods(CniPrintStream out) throws IOException
+ {
+ makeVtable();
+
+ // A given method is either static, overrides a super method, or
+ // is already in vtable order.
+ Iterator<?> i = methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode m = (MethodNode) i.next();
+ String nameToUse;
+ String sum = m.name + m.desc;
+ if (bridgeTargets.contains(sum))
+ nameToUse = (String) methodNameMap.get(sum);
+ else
+ nameToUse = m.name;
+ methodNameMap.put(sum, nameToUse);
+ MethodHelper.print(out, m, this, nameToUse);
+ }
+ }
+
+ private void printTextList(PrintStream out, int what, ArrayList<Text> textList)
+ {
+ if (textList == null)
+ return;
+ Iterator<Text> i = textList.iterator();
+ boolean first = true;
+ while (i.hasNext())
+ {
+ Text item = i.next();
+ if (item.type == what)
+ {
+ if (first)
+ {
+ out.println();
+ first = false;
+ }
+ if (what == Text.FRIEND)
+ out.print(" friend ");
+ out.println(item.text);
+ }
+ }
+ }
+
+ public void print(CniPrintStream out)
+ {
+ out.print("::");
+ out.printName(name);
+ }
+
+ // This prints the body of a class to a CxxPrintStream.
+ private void printContents(CniPrintStream out, ArrayList<Text> textList)
+ throws IOException
+ {
+ printTextList(out, Text.PREPEND, textList);
+ out.println();
+
+ out.print("class ");
+ // Don't use our print() -- we don't want the leading "::".
+ out.printName(name);
+ if (superClass != null)
+ {
+ out.print(" : public ");
+ superClass.print(out);
+ }
+ out.println();
+ out.println("{");
+
+ printTextList(out, Text.ADD, textList);
+ out.println();
+
+ // Note: methods must come first, as we build the list
+ // of method names while printing them.
+ printMethods(out);
+ printFields(out);
+
+ out.setModifiers(Modifier.PUBLIC);
+ out.println(" static ::java::lang::Class class$;");
+
+ printTextList(out, Text.FRIEND, textList);
+
+ out.print("}");
+ if (Modifier.isInterface(access))
+ out.print(" __attribute__ ((java_interface))");
+ out.println(";");
+
+ printTextList(out, Text.APPEND, textList);
+ }
+
+ public void printFully(PrintStream out) throws IOException
+ {
+ linkSupers();
+
+ ArrayList<Text> textList = classpath.getClassTextList(name);
+
+ out.println("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-");
+ out.println();
+ String xname = "__" + name.replaceAll("/", "_") + "__";
+ out.println("#ifndef " + xname);
+ out.println("#define " + xname);
+ out.println();
+ out.println("#pragma interface");
+ out.println();
+
+ if (superClass != null)
+ {
+ out.print("#include <");
+ out.print(superName);
+ out.println(".h>");
+ }
+
+ // Write the body of the stream here. This lets
+ // us emit the namespaces without a second pass.
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ CniPrintStream cxxOut = new CniPrintStream(bytes);
+ cxxOut.addClass(this);
+ printContents(cxxOut, textList);
+ cxxOut.printNamespaces(out);
+ bytes.writeTo(out);
+
+ out.println();
+ out.println("#endif // " + xname);
+ }
+
+ public String toString()
+ {
+ return name;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/CniIncludePrinter.java b/libjava/classpath/tools/gnu/classpath/tools/javah/CniIncludePrinter.java
new file mode 100644
index 000000000..8861541a5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/CniIncludePrinter.java
@@ -0,0 +1,80 @@
+/* CniIncludePrinter.java - generate CNI header files
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public class CniIncludePrinter
+ extends Printer
+{
+ protected CniIncludePrinter(Main classpath, File outFile, boolean isDir,
+ boolean force)
+ {
+ super(classpath, outFile, isDir, force);
+ }
+
+ protected void writePreambleImpl(PrintStream ps)
+ {
+ // does nothing
+ }
+
+ protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+ ClassWrapper klass)
+ {
+ return new PrintStream(fos);
+ }
+
+ public void printClass(File file, ClassWrapper klass) throws IOException
+ {
+ // Never write Object or Class. This is a hack, maybe
+ // the user would like to see what they look like...
+ if (klass.name.equals("java/lang/Object")
+ || klass.name.equals("java/lang/Class"))
+ return;
+ PrintStream ps = getPrintStream(file + ".h", klass);
+ if (ps == null)
+ return;
+ ps.println();
+ klass.printFully(ps);
+ ps.close();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/CniPrintStream.java b/libjava/classpath/tools/gnu/classpath/tools/javah/CniPrintStream.java
new file mode 100644
index 000000000..df2b723e7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/CniPrintStream.java
@@ -0,0 +1,274 @@
+/* CniPrintStream.java - PrintStream that emits CNI declarations
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.objectweb.asm.Type;
+
+public class CniPrintStream
+ extends PrintStream
+{
+ int currentModifiers = Modifier.PRIVATE;
+
+ // True if we saw an array type.
+ boolean sawArray;
+
+ // All the classes referenced by this header.
+ HashSet<String> allClasses = new HashSet<String>();
+
+ String[] previousPackage = new String[0];
+
+ public CniPrintStream(OutputStream out)
+ {
+ super(out);
+ }
+
+ public void addClass(ClassWrapper cw)
+ {
+ allClasses.add(cw.name);
+ }
+
+ public void setModifiers(int newMods)
+ {
+ newMods &= (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE);
+ if (newMods != currentModifiers)
+ {
+ switch (newMods)
+ {
+ case Modifier.PUBLIC:
+ println("public:");
+ break;
+ case Modifier.PROTECTED:
+ println("public: // actually protected");
+ break;
+ case Modifier.PRIVATE:
+ println("private:");
+ break;
+ default:
+ println("public: // actually package-private");
+ break;
+ }
+ currentModifiers = newMods;
+ }
+ }
+
+ private String getName(Type type)
+ {
+ if (type == Type.BOOLEAN_TYPE)
+ return "jboolean";
+ else if (type == Type.BYTE_TYPE)
+ return "jbyte";
+ else if (type == Type.CHAR_TYPE)
+ return "jchar";
+ else if (type == Type.SHORT_TYPE)
+ return "jshort";
+ else if (type == Type.INT_TYPE)
+ return "jint";
+ else if (type == Type.LONG_TYPE)
+ return "jlong";
+ else if (type == Type.FLOAT_TYPE)
+ return "jfloat";
+ else if (type == Type.DOUBLE_TYPE)
+ return "jdouble";
+ else
+ {
+ assert type == Type.VOID_TYPE;
+ return "void";
+ }
+ }
+
+ public String getClassName(Type type)
+ {
+ String name = type.toString();
+ name = name.substring(1, name.length() - 1);
+ // Add the plain class name; we'll handle it when
+ // we process namespaces.
+ allClasses.add(name);
+ return name;
+ }
+
+ // Print the C++ form of TYPE, mangling C++ keywords.
+ public void print(Type type)
+ {
+ int arrayCount = 0;
+ if (type.getSort() == Type.ARRAY)
+ {
+ arrayCount = type.getDimensions();
+ for (int i = 0; i < arrayCount; ++i)
+ print("JArray< ");
+ type = type.getElementType();
+ sawArray = true;
+ }
+ if (type.getSort() == Type.OBJECT)
+ {
+ print("::");
+ printName(getClassName(type));
+ print(" *");
+ }
+ else
+ {
+ print(getName(type));
+ }
+ if (arrayCount > 0)
+ {
+ while (arrayCount-- > 0)
+ {
+ print(" > *");
+ }
+ }
+ }
+
+ // Print NAME, converting into C++ syntax and mangling C++ keywords
+ // as we go.
+ public final static void printName(PrintStream out, String name)
+ {
+ String[] parts = name.split("::|/");
+ for (int i = 0; i < parts.length; i++)
+ {
+ if (i != 0)
+ out.print("::");
+ out.print(Keywords.getCxxName(parts[i]));
+ }
+ }
+
+ // Println NAME, converting into C++ syntax and mangling C++
+ // keywords as we go.
+ public final static void printlnName(PrintStream out, String name)
+ {
+ printName(out, name);
+ out.println();
+ }
+
+ // Print NAME, converting into C++ syntax and mangling C++ keywords
+ // as we go.
+ final void printName(String name)
+ {
+ printName(this, name);
+ }
+
+ private void indent(PrintStream out, int n)
+ {
+ for (int i = 0; i < n; ++i)
+ {
+ out.print(" ");
+ }
+ }
+
+ private void moveToPackage(PrintStream out, String[] pkgParts)
+ {
+ // Find greatest common part.
+ int commonIndex;
+ for (commonIndex = 0; commonIndex < previousPackage.length; ++commonIndex)
+ {
+ if (commonIndex >= pkgParts.length)
+ break;
+ if (! previousPackage[commonIndex].equals(pkgParts[commonIndex]))
+ break;
+ }
+ // Close old parts after the common part.
+ for (int j = previousPackage.length - 1; j >= commonIndex; --j)
+ {
+ indent(out, j + 1);
+ out.println("}");
+ }
+ // Open new parts.
+ for (int j = commonIndex; j < pkgParts.length; ++j)
+ {
+ indent(out, j + 1);
+ out.print("namespace ");
+ printlnName(out, pkgParts[j]);
+ indent(out, j + 1);
+ out.println("{");
+ }
+ previousPackage = pkgParts;
+ }
+
+ private void writeClass(PrintStream out, String klass)
+ {
+ int index = klass.lastIndexOf('/');
+ String pkg = index == -1 ? "" : klass.substring(0, index);
+ String[] pkgParts = index == -1 ? new String[0] : pkg.split("/");
+ String className = index == -1 ? klass : klass.substring(index + 1);
+ moveToPackage(out, pkgParts);
+ indent(out, pkgParts.length + 2);
+ out.print("class ");
+ printName(out, className);
+ out.println(";");
+ }
+
+ public void printNamespaces(PrintStream out)
+ {
+ if (sawArray)
+ {
+ out.println("#include <gcj/array.h>");
+ out.println();
+ }
+
+ String[] classes = allClasses.toArray(new String[0]);
+ Arrays.sort(classes);
+
+ boolean first = true;
+ boolean seen = false;
+ for (int i = 0; i < classes.length; ++i)
+ {
+ String klass = classes[i];
+ if (klass.startsWith("java/lang/") || klass.startsWith("java/io/")
+ || klass.startsWith("java/util/"))
+ continue;
+ if (first)
+ {
+ out.println("extern \"Java\"");
+ out.println("{");
+ first = false;
+ seen = true;
+ }
+ writeClass(out, klass);
+ }
+ if (seen)
+ {
+ moveToPackage(out, new String[0]);
+ out.println("}");
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java b/libjava/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java
new file mode 100644
index 000000000..9b5dc2c36
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java
@@ -0,0 +1,129 @@
+/* CniStubPrinter.java - Generate a CNI stub file
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+public class CniStubPrinter
+ extends Printer
+{
+ protected CniStubPrinter(Main classpath, File outFile, boolean isDir,
+ boolean force)
+ {
+ super(classpath, outFile, isDir, force);
+ }
+
+ private void printDecl(CniPrintStream out, String className, MethodNode method)
+ {
+ out.printName(className);
+ out.print("::");
+ out.printName(method.name);
+ out.print("(");
+ Type[] argTypes = Type.getArgumentTypes(method.desc);
+ for (int j = 0; j < argTypes.length; ++j)
+ {
+ if (j > 0)
+ out.print(", ");
+ out.print(argTypes[j]);
+ }
+ out.print(")");
+ }
+
+ protected void writePreambleImpl(PrintStream out)
+ {
+ out.println("// This file is intended to give you a head start on implementing native");
+ out.println("// methods using CNI.");
+ out.println("// Be aware: running 'gcjh -stubs' once more for this class may");
+ out.println("// overwrite any edits you have made to this file.");
+ out.println();
+ out.println("#include <gcj/cni.h>");
+ out.println("#include <java/lang/UnsupportedOperationException.h>");
+ }
+
+ protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+ ClassWrapper klass)
+ {
+ return new CniPrintStream(fos);
+ }
+
+ public void printClass(File filename, ClassWrapper klass) throws IOException
+ {
+ if (! klass.hasNativeMethod())
+ return;
+ String className = klass.name.replaceAll("/", "::");
+ CniPrintStream out = (CniPrintStream) getPrintStream(filename + ".cc",
+ klass);
+ if (out == null)
+ return;
+ out.println();
+ out.println("#include <" + klass.name + ".h>");
+ out.println();
+
+ Iterator<?> i = klass.methods.iterator();
+ boolean first = true;
+ while (i.hasNext())
+ {
+ MethodNode method = (MethodNode) i.next();
+ if (! Modifier.isNative(method.access))
+ continue;
+ if (! first)
+ out.println();
+ first = false;
+ out.print(Type.getReturnType(method.desc));
+ out.println();
+ printDecl(out, className, method);
+ out.println();
+ out.println("{");
+ out.print(" throw new ::java::lang::UnsupportedOperationException(");
+ out.print("JvNewStringLatin1 (\"");
+ printDecl(out, className, method);
+ out.println("\"));");
+ out.println("}");
+ }
+ out.close();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/FieldHelper.java b/libjava/classpath/tools/gnu/classpath/tools/javah/FieldHelper.java
new file mode 100644
index 000000000..84b1fce8b
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/FieldHelper.java
@@ -0,0 +1,99 @@
+/* FieldHelper.java - field helper methods for CNI
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.lang.reflect.Modifier;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.FieldNode;
+
+public class FieldHelper
+{
+ public static boolean print(CniPrintStream out, FieldNode field,
+ ClassWrapper superType, boolean hasMethodName)
+ {
+ out.setModifiers(field.access);
+ out.print(" ");
+ if (Modifier.isStatic(field.access))
+ out.print("static ");
+ if ((field.value instanceof Integer) || (field.value instanceof Long))
+ out.print("const ");
+ out.print(Type.getType(field.desc));
+ out.print(" ");
+ if (Modifier.isVolatile(field.access))
+ out.print("volatile ");
+ boolean result = false;
+ if (superType != null && ! Modifier.isStatic(field.access))
+ {
+ out.print("__attribute__((aligned(__alignof__( ");
+ superType.print(out);
+ out.print(")))) ");
+ result = true;
+ }
+ out.printName(field.name);
+ if (hasMethodName)
+ out.print("__");
+ if (Modifier.isStatic(field.access))
+ {
+ if (field.value instanceof Integer)
+ {
+ out.print(" = ");
+ int val = ((Integer) field.value).intValue();
+ if (val == Integer.MIN_VALUE)
+ out.print("-" + Integer.MAX_VALUE + " - 1");
+ else
+ out.print(val);
+ }
+ else if (field.value instanceof Long)
+ {
+ out.print(" = ");
+ long val = ((Long) field.value).longValue();
+ if (val == Long.MIN_VALUE)
+ out.print("-" + Long.MAX_VALUE + "LL - 1");
+ else
+ {
+ out.print(val);
+ out.print("LL");
+ }
+ }
+ }
+ out.println(";");
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/GcjhMain.java b/libjava/classpath/tools/gnu/classpath/tools/javah/GcjhMain.java
new file mode 100644
index 000000000..bf466484d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/GcjhMain.java
@@ -0,0 +1,153 @@
+/* GcjhMain.java - gcjh main program
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class GcjhMain extends Main
+{
+ ArrayList<Text> commands = new ArrayList<Text>();
+
+ public GcjhMain()
+ {
+ cni = true;
+ }
+
+ protected String getName()
+ {
+ return "gcjh";
+ }
+
+ protected ClasspathToolParser getParser()
+ {
+ ClasspathToolParser result = super.getParser();
+
+ result.setHeader("usage: gcjh [OPTION]... CLASS...");
+
+ OptionGroup text = new OptionGroup("CNI text options");
+ text.add(new Option("add", "Insert TEXT into class body", "TEXT")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ commands.add(new Text(Text.ADD, arg));
+ }
+ });
+ text.add(new Option("append", "Append TEXT after class declaration",
+ "TEXT")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ commands.add(new Text(Text.APPEND, arg));
+ }
+ });
+ text.add(new Option("friend", "Insert TEXT as a 'friend' declaration",
+ "TEXT")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ commands.add(new Text(Text.FRIEND, arg));
+ }
+ });
+ text.add(new Option("prepend", "Insert TEXT before start of class", "TEXT")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ commands.add(new Text(Text.PREPEND, arg));
+ }
+ });
+ result.add(text);
+
+ OptionGroup compat = new OptionGroup("Compatibility options (unused)");
+ // gcjh itself had compatibility options -old and -trace. I
+ // didn't add them here since they should really be unused by now.
+ compat.add(new Option("td", "Unused compatibility option", "DIRECTORY")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ }
+ });
+ // I don't believe anyone ever used these options.
+ compat.add(new Option("M", "Unused compatibility option")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ }
+ });
+ compat.add(new Option("MM", "Unused compatibility option")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ }
+ });
+ compat.add(new Option("MD", "Unused compatibility option")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ }
+ });
+ compat.add(new Option("MMD", "Unused compatibility option")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ }
+ });
+
+ result.add(compat);
+
+ return result;
+ }
+
+ protected void postParse(String[] names)
+ {
+ for (int i = 0; i < names.length; ++i)
+ textMap.put(names[i].replace('.', '/'), commands);
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ new GcjhMain().run(args);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/JniHelper.java b/libjava/classpath/tools/gnu/classpath/tools/javah/JniHelper.java
new file mode 100644
index 000000000..9225444be
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/JniHelper.java
@@ -0,0 +1,120 @@
+/* JniHelper.java - name mangling and other JNI support
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.IOException;
+
+import org.objectweb.asm.Type;
+
+public class JniHelper
+{
+ public static String getName(Main classpath, Type type) throws IOException
+ {
+ if (type == Type.BOOLEAN_TYPE)
+ return "jboolean";
+ else if (type == Type.BYTE_TYPE)
+ return "jbyte";
+ else if (type == Type.CHAR_TYPE)
+ return "jchar";
+ else if (type == Type.SHORT_TYPE)
+ return "jshort";
+ else if (type == Type.INT_TYPE)
+ return "jint";
+ else if (type == Type.LONG_TYPE)
+ return "jlong";
+ else if (type == Type.FLOAT_TYPE)
+ return "jfloat";
+ else if (type == Type.DOUBLE_TYPE)
+ return "jdouble";
+ else if (type == Type.VOID_TYPE)
+ return "void";
+
+ if (type.getSort() == Type.ARRAY)
+ {
+ Type elt = type.getElementType();
+ int eltSort = elt.getSort();
+ if (type.getDimensions() == 1 && eltSort != Type.OBJECT)
+ return getName(classpath, elt) + "Array";
+ return "jobjectArray";
+ }
+
+ // assert type.getSort() == Type.OBJECT;
+ String className = type.getClassName();
+ // FIXME: is this correct?
+ if (className.equals("java/lang/Class")
+ || className.equals("java.lang.Class"))
+ return "jclass";
+ if (className.equals("java/lang/String")
+ || className.equals("java.lang.String"))
+ return "jstring";
+
+ ClassWrapper klass = classpath.getClass(className);
+ if (klass.isThrowable())
+ return "jthrowable";
+ return "jobject";
+ }
+
+ public static String mangle(String name)
+ {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < name.length(); ++i)
+ {
+ char c = name.charAt(i);
+ if (c == '_')
+ result.append("_1");
+ else if (c == ';')
+ result.append("_2");
+ else if (c == '[')
+ result.append("_3");
+ else if (c == '/')
+ result.append("_");
+ else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z'))
+ result.append(c);
+ else
+ {
+ result.append("_0");
+ // Sigh.
+ String hex = "0000" + Integer.toHexString(c);
+ result.append(hex.substring(hex.length() - 4));
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/JniIncludePrinter.java b/libjava/classpath/tools/gnu/classpath/tools/javah/JniIncludePrinter.java
new file mode 100644
index 000000000..cb8bcd8d9
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/JniIncludePrinter.java
@@ -0,0 +1,169 @@
+/* JniIncludePrinter.java - Generate a JNI header file
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+public class JniIncludePrinter
+ extends Printer
+{
+ protected JniIncludePrinter(Main classpath, File outFile, boolean isDir,
+ boolean force)
+ {
+ super(classpath, outFile, isDir, force);
+ }
+
+ private void writeFields(ClassWrapper klass, JniPrintStream out)
+ throws IOException
+ {
+ klass.linkSupers();
+ boolean wroteAny = false;
+ for (; klass != null; klass = klass.superClass)
+ {
+ Iterator<?> i = klass.fields.iterator();
+ while (i.hasNext())
+ {
+ FieldNode field = (FieldNode) i.next();
+ if (! Modifier.isStatic(field.access)
+ || ! Modifier.isFinal(field.access))
+ continue;
+ if (! (field.value instanceof Integer)
+ && ! (field.value instanceof Long))
+ continue;
+
+ // Note that we don't want to mangle the field name.
+ String name = (JniHelper.mangle(klass.name) + "_" + field.name);
+ out.print("#undef ");
+ out.println(name);
+ out.print("#define ");
+ out.print(name);
+ out.print(" ");
+ out.print(field.value);
+ if (field.value instanceof Integer)
+ out.print("L");
+ else if (field.value instanceof Long)
+ out.print("LL");
+ out.println();
+ wroteAny = true;
+ }
+ }
+ if (wroteAny)
+ out.println();
+ }
+
+ protected void writePreambleImpl(PrintStream out)
+ {
+ out.println("/* DO NOT EDIT THIS FILE - it is machine generated */");
+ out.println();
+ out.println("#include <jni.h>");
+ }
+
+ protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+ ClassWrapper klass)
+ {
+ return new JniPrintStream(classpath, fos, klass);
+ }
+
+ public void printClass(File file, ClassWrapper klass) throws IOException
+ {
+ // Note that we ignore the filename here.
+ String xname = JniHelper.mangle(klass.name);
+
+ // mangle the filename a bit
+ String filename = klass.name;
+
+ filename = filename.replace('/', '_');
+ filename = filename.replace('$', '_');
+ filename = filename + ".h";
+
+ JniPrintStream out = (JniPrintStream) getPrintStream(filename, klass);
+
+ if (out == null)
+ return;
+
+ out.println();
+ out.print("#ifndef __");
+ out.print(xname);
+ out.println("__");
+ out.print("#define __");
+ out.print(xname);
+ out.println("__");
+ out.println();
+ out.println("#ifdef __cplusplus");
+ out.println("extern \"C\"");
+ out.println("{");
+ out.println("#endif");
+ out.println();
+
+ Iterator<?> i = klass.methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode method = (MethodNode) i.next();
+ if (! Modifier.isNative(method.access))
+ continue;
+ out.print("JNIEXPORT ");
+ out.print(Type.getReturnType(method.desc));
+ out.print(" JNICALL ");
+ out.print(method, xname);
+ out.println(";");
+ }
+
+ out.println();
+
+ writeFields(klass, out);
+
+ out.println("#ifdef __cplusplus");
+ out.println("}");
+ out.println("#endif");
+ out.println();
+ out.print("#endif /* __");
+ out.print(xname);
+ out.println("__ */");
+ out.close();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/JniPrintStream.java b/libjava/classpath/tools/gnu/classpath/tools/javah/JniPrintStream.java
new file mode 100644
index 000000000..96f9e7d1a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/JniPrintStream.java
@@ -0,0 +1,115 @@
+/* JniPrintStream.java - PrintStream that emits JNI declarations
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+public class JniPrintStream
+ extends PrintStream
+{
+ Main classpath;
+
+ // This is used to determine whether a method has an overload.
+ HashMap<String,Integer> methodNameMap = new HashMap<String,Integer>();
+
+ public JniPrintStream(Main classpath, OutputStream out, ClassWrapper klass)
+ {
+ super(out);
+ this.classpath = classpath;
+ computeOverloads(klass);
+ }
+
+ private void computeOverloads(ClassWrapper klass)
+ {
+ Iterator<?> i = klass.methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode method = (MethodNode) i.next();
+ if (! Modifier.isNative(method.access))
+ continue;
+ if (methodNameMap.containsKey(method.name))
+ {
+ Integer val = methodNameMap.get(method.name);
+ methodNameMap.put(method.name, Integer.valueOf(val.intValue() + 1));
+ }
+ else
+ methodNameMap.put(method.name, Integer.valueOf(1));
+ }
+ }
+
+ public void print(Type type) throws IOException
+ {
+ print(JniHelper.getName(classpath, type));
+ }
+
+ public void print(MethodNode method, String className) throws IOException
+ {
+ print("Java_");
+ print(className);
+ print("_");
+ print(JniHelper.mangle(method.name));
+ Integer overloadCount = (Integer) methodNameMap.get(method.name);
+ if (overloadCount.intValue() > 1)
+ {
+ print("__");
+ int lastOffset = method.desc.lastIndexOf(')');
+ print(JniHelper.mangle(method.desc.substring(1, lastOffset)));
+ }
+ print(" (JNIEnv *env");
+ if (Modifier.isStatic(method.access))
+ print(", jclass");
+ else
+ print(", jobject");
+ Type[] types = Type.getArgumentTypes(method.desc);
+ for (int i = 0; i < types.length; ++i)
+ {
+ print(", ");
+ print(types[i]);
+ }
+ print(")");
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/JniStubPrinter.java b/libjava/classpath/tools/gnu/classpath/tools/javah/JniStubPrinter.java
new file mode 100644
index 000000000..4a1803a27
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/JniStubPrinter.java
@@ -0,0 +1,109 @@
+/* JniStubPrinter.java - Generate JNI stub files
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+public class JniStubPrinter
+ extends Printer
+{
+ protected JniStubPrinter(Main classpath, File outFile, boolean isDir,
+ boolean force)
+ {
+ super(classpath, outFile, isDir, force);
+ }
+
+ protected void writePreambleImpl(PrintStream out)
+ {
+ out.println("/* This file is intended to give you a head start on implementing native");
+ out.println(" methods using JNI.");
+ out.println(" Be aware: running gcjh or compatible tool with '-stubs' option once more");
+ out.println(" for the same input may overwrite any edits you have made to this file. */");
+ }
+
+ protected PrintStream getPrintStreamImpl(FileOutputStream fos,
+ ClassWrapper klass)
+ {
+ return new JniPrintStream(classpath, fos, klass);
+ }
+
+ public void printClass(File filename, ClassWrapper klass) throws IOException
+ {
+ // Note that we ignore the filename here.
+ if (! klass.hasNativeMethod())
+ return;
+ String xname = JniHelper.mangle(klass.name);
+ JniPrintStream out
+ = (JniPrintStream) getPrintStream(klass.name.replace('/', '_') + ".c",
+ klass);
+ if (out == null)
+ return;
+ out.println();
+ out.print("#include <");
+ out.print(klass.name.replace('/', '_'));
+ out.println(".h>");
+
+ Iterator<?> i = klass.methods.iterator();
+ while (i.hasNext())
+ {
+ MethodNode method = (MethodNode) i.next();
+ if (! Modifier.isNative(method.access))
+ continue;
+ out.println();
+ out.print(Type.getReturnType(method.desc));
+ out.println();
+ out.print(method, xname);
+ out.println();
+ out.println("{");
+ out.print(" (*env)->FatalError (env, \"");
+ out.print(method, xname);
+ out.println(" not implemented\");");
+ out.println("}");
+ }
+ out.close();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/Keywords.java b/libjava/classpath/tools/gnu/classpath/tools/javah/Keywords.java
new file mode 100644
index 000000000..9c76a3660
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/Keywords.java
@@ -0,0 +1,172 @@
+/* Keywords.java - List of C++ keywords
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.util.HashSet;
+
+public class Keywords
+{
+/* A sorted list of all C++ keywords. This is identical to the list
+ in gcc/java/mangle.c. */
+ private static final String[] words =
+ {
+ "_Complex",
+ "__alignof",
+ "__alignof__",
+ "__asm",
+ "__asm__",
+ "__attribute",
+ "__attribute__",
+ "__builtin_va_arg",
+ "__complex",
+ "__complex__",
+ "__const",
+ "__const__",
+ "__extension__",
+ "__imag",
+ "__imag__",
+ "__inline",
+ "__inline__",
+ "__label__",
+ "__null",
+ "__real",
+ "__real__",
+ "__restrict",
+ "__restrict__",
+ "__signed",
+ "__signed__",
+ "__typeof",
+ "__typeof__",
+ "__volatile",
+ "__volatile__",
+ "and",
+ "and_eq",
+ "asm",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "class",
+ "compl",
+ "const",
+ "const_cast",
+ "continue",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "else",
+ "enum",
+ "explicit",
+ "export",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "goto",
+ "if",
+ "inline",
+ "int",
+ "long",
+ "mutable",
+ "namespace",
+ "new",
+ "not",
+ "not_eq",
+ "operator",
+ "or",
+ "or_eq",
+ "private",
+ "protected",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_cast",
+ "struct",
+ "switch",
+ "template",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typeid",
+ "typename",
+ "typeof",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "wchar_t",
+ "while",
+ "xor",
+ "xor_eq"
+ };
+
+ private static final HashSet<String> keywords;
+ static
+ {
+ keywords = new HashSet<String>();
+ for (int i = 0; i < words.length; ++i)
+ keywords.add(words[i]);
+ }
+
+ public static String getCxxName(String name)
+ {
+ int i;
+ for (i = name.length() - 1; i >= 0 && name.charAt(i) == '$'; --i)
+ ;
+ if (keywords.contains(name.substring(0, i + 1)))
+ return name + "$";
+ return name;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/Main.java b/libjava/classpath/tools/gnu/classpath/tools/javah/Main.java
new file mode 100644
index 000000000..bec04f00d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/Main.java
@@ -0,0 +1,468 @@
+/* Main.java - javah main program
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.objectweb.asm.ClassReader;
+
+public class Main
+{
+ // This is an option group for classpath-related options,
+ // and also is used for loading classes.
+ PathOptionGroup classpath = new PathOptionGroup();
+
+ // The output directory.
+ String outputDir;
+
+ // The output file name used if/when -o option is used.
+ String outFileName;
+
+ // The loader that we use to load class files.
+ URLClassLoader loader;
+
+ // In -all mode, the name of the directory to scan.
+ String allDirectory;
+
+ // True for verbose mode.
+ boolean verbose;
+
+ // True if we're emitting stubs.
+ boolean stubs;
+
+ // True if we're emitting CNI code.
+ boolean cni;
+
+ // True if we've seen -cni or -jni.
+ boolean cniOrJniSeen;
+
+ // True if output files should always be written.
+ boolean force;
+
+ // Map class names to class wrappers.
+ HashMap<String,ClassWrapper> classMap = new HashMap<String,ClassWrapper>();
+
+ // Map class names to lists of Text objects.
+ HashMap<String,ArrayList<Text>> textMap = new HashMap<String,ArrayList<Text>>();
+
+ void readCommandFile(String textFileName) throws OptionException
+ {
+ FileInputStream fis;
+ try
+ {
+ fis = new FileInputStream(textFileName);
+ }
+ catch (FileNotFoundException ignore)
+ {
+ throw new OptionException("file \"" + textFileName + "\" not found");
+ }
+ BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
+ String currentClass = null;
+ ArrayList<Text> currentValues = null;
+ while (true)
+ {
+ String line;
+ try
+ {
+ line = reader.readLine();
+ }
+ catch (IOException _)
+ {
+ break;
+ }
+ if (line == null)
+ break;
+ line = line.trim();
+ if (line.length() == 0 || line.charAt(0) == '#')
+ continue;
+ int index = line.indexOf(' ');
+ String cmd = line.substring(0, index);
+ String value = line.substring(index + 1);
+ int cmdValue;
+ if ("class".equals(cmd))
+ {
+ if (currentClass != null)
+ {
+ textMap.put(currentClass, currentValues);
+ }
+ currentClass = value;
+ currentValues = new ArrayList<Text>();
+ continue;
+ }
+ if (currentClass == null)
+ throw new OptionException("no class set");
+ if ("add".equals(cmd))
+ cmdValue = Text.ADD;
+ else if ("append".equals(cmd))
+ cmdValue = Text.APPEND;
+ else if ("prepend".equals(cmd))
+ cmdValue = Text.PREPEND;
+ else if ("friend".equals(cmd))
+ cmdValue = Text.FRIEND;
+ else
+ throw new OptionException("unrecognized command: " + cmd);
+ currentValues.add(new Text(cmdValue, value));
+ }
+ if (currentClass != null)
+ {
+ textMap.put(currentClass, currentValues);
+ }
+ }
+
+ void scanDirectory(File dir, final HashSet<Object> results)
+ {
+ File[] files = dir.listFiles(new FileFilter()
+ {
+ public boolean accept(File pathname)
+ {
+ if (pathname.isDirectory())
+ {
+ scanDirectory(pathname, results);
+ return false;
+ }
+ return pathname.getName().endsWith(".class");
+ }
+ });
+ if (files != null)
+ results.addAll(Arrays.asList(files));
+ }
+
+ protected String getName()
+ {
+ return "javah";
+ }
+
+ protected ClasspathToolParser getParser()
+ {
+ ClasspathToolParser result = new ClasspathToolParser(getName(), true);
+ result.setHeader("usage: javah [OPTIONS] CLASS...");
+ result.add(classpath);
+ result.add(new Option('d', "Set output directory", "DIR")
+ {
+ public void parsed(String dir) throws OptionException
+ {
+ if (outputDir != null)
+ throw new OptionException("-d already seen");
+ if (outFileName != null)
+ throw new OptionException("only one of -d or -o may be used");
+ outputDir = dir;
+ }
+ });
+ result.add(new Option('o',
+ "Set output file (only one of -d or -o may be used)",
+ "FILE")
+ {
+ public void parsed(String fileName) throws OptionException
+ {
+ if (outFileName != null)
+ throw new OptionException("-o already seen");
+ if (outputDir != null)
+ throw new OptionException("only one of -d or -o may be used");
+ outFileName = fileName;
+ }
+ });
+ result.add(new Option("cmdfile", "Read command file", "FILE")
+ {
+ public void parsed(String file) throws OptionException
+ {
+ readCommandFile(file);
+ }
+ });
+ result.add(new Option("all", "Operate on all class files under directory",
+ "DIR")
+ {
+ public void parsed(String arg) throws OptionException
+ {
+ // FIXME: lame restriction...
+ if (allDirectory != null)
+ throw new OptionException("-all already specified");
+ allDirectory = arg;
+ }
+ });
+ result.add(new Option("stubs", "Emit stub implementation")
+ {
+ public void parsed(String arg0) throws OptionException
+ {
+ stubs = true;
+ }
+ });
+ result.add(new Option("jni", "Emit JNI stubs or header (default)")
+ {
+ public void parsed(String arg0) throws OptionException
+ {
+ if (cniOrJniSeen && cni)
+ throw new OptionException("only one of -jni or -cni may be used");
+ cniOrJniSeen = true;
+ cni = false;
+ }
+ });
+ result.add(new Option("cni", "Emit CNI stubs or header (default JNI)")
+ {
+ public void parsed(String arg0) throws OptionException
+ {
+ if (cniOrJniSeen && ! cni)
+ throw new OptionException("only one of -jni or -cni may be used");
+ cniOrJniSeen = true;
+ cni = true;
+ }
+ });
+ result.add(new Option("verbose", 'v', "Set verbose mode")
+ {
+ public void parsed(String arg0) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(new Option("force", "Output files should always be written")
+ {
+ public void parsed(String arg0) throws OptionException
+ {
+ force = true;
+ }
+ });
+ return result;
+ }
+
+ private File makeOutputDirectory() throws IOException
+ {
+ File outputFile;
+ if (outputDir == null)
+ outputFile = new File(".");
+ else
+ outputFile = new File(outputDir);
+ return outputFile;
+ }
+
+ /**
+ * @return The {@link File} object where the generated code will be written.
+ * Returns <code>null</code> if the option <code>-force</code> was
+ * specified on the command line and the designated file already
+ * exists.
+ * @throws IOException if <code>outFileName</code> is not a writable file.
+ */
+ private File makeOutputFile() throws IOException
+ {
+ File result = new File(outFileName);
+ if (result.exists())
+ {
+ if (! result.isFile())
+ throw new IOException("'" + outFileName + "' is not a file");
+ if (! force)
+ {
+ if (verbose)
+ System.err.println("["+ outFileName
+ + " already exists. Use -force to overwrite]");
+ return null;
+ }
+ if (! result.delete())
+ throw new IOException("Was unable to delete existing file: "
+ + outFileName);
+ }
+ return result;
+ }
+
+ private void writeHeaders(HashMap<File,ClassWrapper> klasses, Printer printer)
+ throws IOException
+ {
+ Iterator<Map.Entry<File,ClassWrapper>> i = klasses.entrySet().iterator();
+ while (i.hasNext())
+ {
+ Map.Entry<File,ClassWrapper> e = i.next();
+ File file = e.getKey();
+ ClassWrapper klass = e.getValue();
+ if (verbose)
+ System.err.println("[writing " + klass + " as " + file + "]");
+ printer.printClass(file, klass);
+ }
+ }
+
+ protected void postParse(String[] names)
+ {
+ // Nothing here.
+ }
+
+ protected void run(String[] args) throws IOException
+ {
+ ClasspathToolParser p = getParser();
+ String[] classNames = p.parse(args, true);
+ postParse(classNames);
+ loader = classpath.getLoader();
+
+ boolean isDirectory = outFileName == null;
+ File outputFile = isDirectory ? makeOutputDirectory() : makeOutputFile();
+ if (outputFile == null)
+ return;
+
+ Printer printer;
+ if (! cni)
+ {
+ if (stubs)
+ printer = new JniStubPrinter(this, outputFile, isDirectory, force);
+ else
+ printer = new JniIncludePrinter(this, outputFile, isDirectory, force);
+ }
+ else
+ {
+ if (stubs)
+ printer = new CniStubPrinter(this, outputFile, isDirectory, force);
+ else
+ printer = new CniIncludePrinter(this, outputFile, isDirectory, force);
+ }
+
+ // First we load all of the files. That way if
+ // there are references between the files we will
+ // be loading the set that the user asked for.
+ HashSet<Object> klasses = new HashSet<Object>();
+ if (allDirectory != null)
+ scanDirectory(new File(allDirectory), klasses);
+ // Add the command-line arguments. We use the type of
+ // an item in 'klasses' to decide how to load each class.
+ for (int i = 0; i < classNames.length; ++i)
+ {
+ if (classNames[i].endsWith(".class"))
+ {
+ klasses.add(new File(classNames[i]));
+ }
+ else
+ {
+ klasses.add(classNames[i]);
+ }
+ }
+
+ Iterator<Object> i = klasses.iterator();
+ HashMap<File,ClassWrapper> results = new HashMap<File,ClassWrapper>();
+ while (i.hasNext())
+ {
+ // Let user specify either kind of class name or a
+ // file name.
+ Object item = i.next();
+ ClassWrapper klass;
+ File filename;
+ if (item instanceof File)
+ {
+ // Load class from file.
+ if (verbose)
+ System.err.println("[reading file " + item + "]");
+ klass = getClass((File) item);
+ filename = new File(klass.name);
+ }
+ else
+ {
+ // Load class given the class name.
+ String className = ((String) item).replace('.', '/');
+ if (verbose)
+ System.err.println("[reading class " + className + "]");
+ // Use the name the user specified, even if it is
+ // different from the ultimate class name.
+ filename = new File(className);
+ klass = getClass(className);
+ }
+ results.put(filename, klass);
+ }
+
+ writeHeaders(results, printer);
+ }
+
+ public ArrayList<Text> getClassTextList(String name)
+ {
+ return textMap.get(name);
+ }
+
+ private ClassWrapper readClass(InputStream is) throws IOException
+ {
+ ClassReader r = new ClassReader(is);
+ ClassWrapper result = new ClassWrapper(this);
+ r.accept(result, true);
+ is.close();
+ return result;
+ }
+
+ private ClassWrapper getClass(File fileName) throws IOException
+ {
+ InputStream is = new FileInputStream(fileName);
+ ClassWrapper result = readClass(is);
+ if (classMap.containsKey(result.name))
+ throw new IllegalArgumentException("class " + result.name
+ + " already loaded");
+ classMap.put(result.name, result);
+ return result;
+ }
+
+ public ClassWrapper getClass(String name) throws IOException
+ {
+ if (! classMap.containsKey(name))
+ {
+ String resource = name.replace('.', '/') + ".class";
+ URL url = loader.findResource(resource);
+ if (url == null)
+ throw new IOException("can't find class file " + resource
+ + " in " + loader);
+ InputStream is = url.openStream();
+ ClassWrapper result = readClass(is);
+ classMap.put(name, result);
+ }
+ return (ClassWrapper) classMap.get(name);
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ Main m = new Main();
+ m.run(args);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/MethodHelper.java b/libjava/classpath/tools/gnu/classpath/tools/javah/MethodHelper.java
new file mode 100644
index 000000000..d65cc93d7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/MethodHelper.java
@@ -0,0 +1,122 @@
+/* MethodHelper.java - helper class for manipulating methods
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+public class MethodHelper
+{
+
+ public static boolean overrides(MethodNode derived, MethodNode base)
+ {
+ if (! derived.name.equals(base.name))
+ return false;
+ if (! derived.desc.equals(base.desc))
+ return false;
+ // FIXME: permission madness?
+ return true;
+ }
+
+ public static String getBridgeTarget(MethodNode meth)
+ {
+ if ((meth.access & Opcodes.ACC_BRIDGE) == 0)
+ return null;
+ Iterator<?> i = meth.instructions.iterator();
+ while (i.hasNext())
+ {
+ AbstractInsnNode insn = (AbstractInsnNode) i.next();
+ if (! (insn instanceof MethodInsnNode))
+ continue;
+ return ((MethodInsnNode) insn).desc;
+ }
+ return null;
+ }
+
+ public static void print(CniPrintStream out, MethodNode meth,
+ ClassWrapper declarer, String realMethodName)
+ {
+ if ("<clinit>".equals(meth.name))
+ return;
+ boolean isInit = "<init>".equals(meth.name);
+ out.setModifiers(meth.access);
+ out.print(" ");
+ if (Modifier.isStatic(meth.access))
+ out.print("static ");
+ // If a class is final then we might as well skip 'virtual'.
+ // The reason here is that it is safe in this case for C++
+ // ABI code to generate a direct call. The method does end
+ // up in the vtable (for BC code) but we don't care. Also,
+ // the class can't be derived from anyway.
+ else if (! isInit && ! Modifier.isPrivate(meth.access)
+ && ! Modifier.isFinal(declarer.access))
+ out.print("virtual ");
+ if (! isInit)
+ {
+ out.print(Type.getReturnType(meth.desc));
+ out.print(" ");
+ out.printName(realMethodName);
+ }
+ else
+ {
+ String name = declarer.name;
+ int index = name.lastIndexOf('/');
+ name = name.substring(index + 1);
+ out.printName(name);
+ }
+ out.print("(");
+ Type[] argTypes = Type.getArgumentTypes(meth.desc);
+ for (int i = 0; i < argTypes.length; ++i)
+ {
+ if (i > 0)
+ out.print(", ");
+ out.print(argTypes[i]);
+ }
+ out.print(")");
+ if (Modifier.isAbstract(meth.access))
+ out.print(" = 0");
+ out.println(";");
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/PackageWrapper.java b/libjava/classpath/tools/gnu/classpath/tools/javah/PackageWrapper.java
new file mode 100644
index 000000000..11b38b20f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/PackageWrapper.java
@@ -0,0 +1,54 @@
+/* PackageWrapper.java - represent a package
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+public class PackageWrapper
+{
+ // This is null if there is no parent package.
+ PackageWrapper parent;
+
+ // Name of this package relative to its parent's name.
+ String name;
+
+ public PackageWrapper(PackageWrapper parent, String name)
+ {
+ this.parent = parent;
+ this.name = name;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/PathOptionGroup.java b/libjava/classpath/tools/gnu/classpath/tools/javah/PathOptionGroup.java
new file mode 100644
index 000000000..8eec4cc60
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/PathOptionGroup.java
@@ -0,0 +1,147 @@
+/* PathOptionGroup.java - handle classpath-setting options
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+public class PathOptionGroup
+ extends OptionGroup
+{
+ ArrayList<String> classpath = new ArrayList<String>();
+
+ ArrayList<String> bootclasspath = new ArrayList<String>();
+
+ void setPath(ArrayList<String> list, String path)
+ {
+ list.clear();
+ StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
+ while (st.hasMoreTokens())
+ {
+ list.add(st.nextToken());
+ }
+ }
+
+ void addExtDirs(ArrayList<String> list, String path)
+ {
+ StringTokenizer tok = new StringTokenizer(path, File.pathSeparator);
+ while (tok.hasMoreTokens())
+ {
+ File dir = new File(tok.nextToken());
+ list.addAll(Arrays.asList(dir.list(new FilenameFilter()
+ {
+ public boolean accept(File dir, String name)
+ {
+ return name.endsWith(".zip") || name.endsWith(".jar");
+ }
+ })));
+ }
+ }
+
+ public PathOptionGroup()
+ {
+ super("Class path options");
+
+ // Use the VM's built-in boot class path by default.
+ String boot = System.getProperty("sun.boot.class.path");
+ if (boot != null)
+ setPath(bootclasspath, boot);
+
+ add(new Option("classpath", "Set the class path", "PATH")
+ {
+ public void parsed(String path) throws OptionException
+ {
+ setPath(classpath, path);
+ }
+ });
+ add(new Option("cp", "Set the class path", "PATH")
+ {
+ public void parsed(String path) throws OptionException
+ {
+ setPath(classpath, path);
+ }
+ });
+ add(new Option('I', "Add directory to class path", "DIR", true)
+ {
+ public void parsed(String path) throws OptionException
+ {
+ classpath.add(path);
+ }
+ });
+ add(new Option("bootclasspath", "Set the boot class path", "PATH")
+ {
+ public void parsed(String path) throws OptionException
+ {
+ setPath(bootclasspath, path);
+ }
+ });
+ add(new Option("extdirs", "Set the extension directory path", "PATH")
+ {
+ public void parsed(String path) throws OptionException
+ {
+ addExtDirs(classpath, path);
+ }
+ });
+ }
+
+ public URLClassLoader getLoader() throws MalformedURLException
+ {
+ ArrayList<URL> urls = new ArrayList<URL>();
+ classpath.addAll(bootclasspath);
+ Iterator<String> i = classpath.iterator();
+ while (i.hasNext())
+ {
+ String f = i.next();
+ urls.add(new File(f).toURL());
+ }
+ URL[] urlArray = urls.toArray(new URL[0]);
+ return new URLClassLoader(urlArray);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/Printer.java b/libjava/classpath/tools/gnu/classpath/tools/javah/Printer.java
new file mode 100644
index 000000000..7a896cf62
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/Printer.java
@@ -0,0 +1,139 @@
+/* Print.java - abstract base class for printing classes
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public abstract class Printer
+{
+ protected Main classpath;
+
+ /**
+ * The {@link File} object that denotes either a directory (when the
+ * <code>-d</code> option was used), or a file (when the <code>-o</code>
+ * option was used) on the command line.
+ */
+ protected File outputFileObject;
+
+ /**
+ * Set to <code>true</code> if the field <code>outputFileObject</code> denotes
+ * a directory; i.e. for each input class file, one JNI header file will be
+ * generated in that directory.
+ * <p>
+ * Set to <code>false</code> if the field <code>outputFileObject</code>
+ * denotes a file; i.e. all generated headers will be written to that file.
+ */
+ protected boolean isDirectory;
+
+ /**
+ * Set to <code>true</code> if the output file(s) should always be written.
+ * <p>
+ * When set to <code>false</code>, the contents of the header/stub are only
+ * written to the file if it does not already exist.
+ */
+ protected boolean force;
+
+ /**
+ * Set to <code>true</code> if all output is directed to one file, and the
+ * common preamble text has already been generated.
+ */
+ protected boolean wrotePreamble;
+
+ protected Printer(Main classpath, File outFile, boolean isDir, boolean force)
+ {
+ this.classpath = classpath;
+ if (outFile == null)
+ throw new IllegalArgumentException("File argument MUST NOT be null");
+ outputFileObject = outFile;
+ isDirectory = isDir;
+ if (! isDirectory)
+ {
+ File parent = outputFileObject.getParentFile();
+ if (parent != null)
+ parent.mkdirs();
+ }
+ this.force = force;
+ }
+
+ public abstract void printClass(File filename, ClassWrapper klass)
+ throws IOException;
+
+ protected abstract void writePreambleImpl(PrintStream ps);
+
+ protected abstract PrintStream getPrintStreamImpl(FileOutputStream fos,
+ ClassWrapper klass);
+
+ protected PrintStream getPrintStream(String fullName, ClassWrapper klass)
+ throws FileNotFoundException
+ {
+ PrintStream result;
+ FileOutputStream fos;
+ if (isDirectory)
+ {
+ File outFile = new File(outputFileObject, fullName);
+ if (outFile.exists() && ! force)
+ return null;
+ File parent = outFile.getParentFile();
+ if (parent != null)
+ parent.mkdirs();
+ fos = new FileOutputStream(outFile);
+ result = getPrintStreamImpl(fos, klass);
+ writePreamble(result);
+ }
+ else
+ {
+ // the first time we open this file, wrotePreamble is false
+ fos = new FileOutputStream(outputFileObject, wrotePreamble);
+ result = getPrintStreamImpl(fos, klass);
+ if (! wrotePreamble)
+ writePreamble(result);
+ }
+ return result;
+ }
+
+ protected void writePreamble(PrintStream out)
+ {
+ writePreambleImpl(out);
+ wrotePreamble = true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/javah/Text.java b/libjava/classpath/tools/gnu/classpath/tools/javah/Text.java
new file mode 100644
index 000000000..37a1ad669
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/javah/Text.java
@@ -0,0 +1,60 @@
+/* Text.java - convenience class for CNI header text insertions
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.javah;
+
+public class Text
+{
+ public static final int ADD = 0;
+
+ public static final int APPEND = 1;
+
+ public static final int FRIEND = 2;
+
+ public static final int PREPEND = 3;
+
+ public int type;
+
+ public String text;
+
+ public Text(int type, String text)
+ {
+ this.type = type;
+ this.text = text;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/CACertCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/CACertCmd.java
new file mode 100644
index 000000000..603385d19
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/CACertCmd.java
@@ -0,0 +1,313 @@
+/* CACertCmd.java -- GNU specific cacert handler
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.logging.Logger;
+
+/**
+ * The <code>-cacert</code> keytol command handler is used to import a CA
+ * trusted X.509 certificate into a key store.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the file containing the trusted CA
+ * certificate to import. If omitted, the tool will process STDIN.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+public class CACertCmd
+ extends Command
+{
+ private static final Logger log = Logger.getLogger(CACertCmd.class.getName());
+ /** Pathname of the file containing the CA certificate to import. */
+ protected String _certFileName;
+ /** Type of the key store to use. */
+ protected String _ksType;
+ /** The URL to the keystore where the trusted certificates will be added. */
+ protected String _ksURL;
+ /** The password protecting the keystore. */
+ protected String _ksPassword;
+ /** Class name of a security provider to use. */
+ protected String _providerClassName;
+ /** Reference to the X.509 factory. */
+ private CertificateFactory x509Factory;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certFileName = pathName;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ /* (non-Javadoc)
+ * @see gnu.classpath.tools.keytool.Command#setup()
+ */
+ void setup() throws Exception
+ {
+ setInputStreamParam(_certFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-cacert handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -file=" + _certFileName); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws CertificateException, KeyStoreException,
+ NoSuchAlgorithmException, IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ alias = getAliasFromFileName(_certFileName);
+ if (store.containsAlias(alias))
+ throw new IllegalArgumentException(Messages.getFormattedString("CACertCmd.0", //$NON-NLS-1$
+ alias));
+ x509Factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+ Certificate certificate = x509Factory.generateCertificate(inStream);
+ if (Configuration.DEBUG)
+ log.fine("certificate = " + certificate); //$NON-NLS-1$
+ store.setCertificateEntry(alias, certificate);
+ saveKeyStore();
+ if (verbose)
+ System.out.println(Messages.getFormattedString("CACertCmd.1", //$NON-NLS-1$
+ new Object[] { _certFileName,
+ alias }));
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /* (non-Javadoc)
+ * @see gnu.classpath.tools.keytool.Command#getParser()
+ */
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.CACERT_CMD, true);
+ result.setHeader(Messages.getString("CACertCmd.2")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("CACertCmd.3")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("CACertCmd.4")); //$NON-NLS-1$
+ options.add(new Option(Main.FILE_OPT,
+ Messages.getString("CACertCmd.5"), //$NON-NLS-1$
+ Messages.getString("CACertCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _certFileName = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("CACertCmd.7"), //$NON-NLS-1$
+ Messages.getString("CACertCmd.8")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("CACertCmd.9"), //$NON-NLS-1$
+ Messages.getString("CACertCmd.10")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("CACertCmd.11"), //$NON-NLS-1$
+ Messages.getString("CACertCmd.12")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("CACertCmd.13"), //$NON-NLS-1$
+ Messages.getString("CACertCmd.14")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("CACertCmd.15")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Construct an Alias string from the name of the file containing the
+ * certificate to import. This method first removes the last dot (".")
+ * character and any subsequent characters from the input name, and then
+ * replaces any space and dot characters with underscores. For example the
+ * input string <code>brasil.gov.br.cert</code> will result in
+ * <code>brasil_gov_br</code> as its alias.
+ *
+ * @param fileName the name of the file containing the CA certificate
+ * @return a string which can, and will, be used as the Alias of this CA
+ * certificate.
+ */
+ private String getAliasFromFileName(String fileName)
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getAliasFromFileName", fileName); //$NON-NLS-1$
+ // get the basename
+ fileName = new File(fileName).getName();
+ // remove '.' if at start
+ if (fileName.startsWith(".")) //$NON-NLS-1$
+ fileName = fileName.substring(1);
+
+ // remove last \..+
+ int ndx = fileName.lastIndexOf('.');
+ if (ndx > 0)
+ fileName = fileName.substring(0, ndx);
+ // replace spaces and dots with underscores
+ char[] chars = fileName.toCharArray();
+ for (int i = 0; i < chars.length; i++)
+ {
+ char c = chars[i];
+ if (c == ' ' || c == '.')
+ chars[i] = '_';
+ }
+ String result = new String(chars);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getAliasFromFileName", result); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/CertReqCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/CertReqCmd.java
new file mode 100644
index 000000000..e14fa4916
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/CertReqCmd.java
@@ -0,0 +1,475 @@
+/* CertReqCmd.java -- The certreq command handler of the keytool
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.security.OID;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.util.Base64;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The <b>-certreq</b> keytool command handler is used to generate a Certificate
+ * Signing Request (CSR) in PKCS#10 format.
+ * <p>
+ * The ASN.1 specification of a CSR, as stated in RFC-2986 is as follows:
+ * <p>
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version INTEGER -- v1(0)
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo,
+ * attributes [0] IMPLICIT Attributes -- see note later
+ * }
+ *
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ * </pre>
+ * <b>IMPORTANT</b>: Some documentation (e.g. RSA examples) claims that the
+ * <code>attributes</code> field is <i>OPTIONAL</i> while <i>RFC-2986</i>
+ * implies the opposite. This implementation considers this field, by default,
+ * as <i>OPTIONAL</i>, unless the option <code>-attributes</code> is included
+ * on the command line.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-sigalg ALGORITHM</dt>
+ * <dd>The canonical name of the digital signature algorithm to use for
+ * signing the certificate. If this option is omitted, a default value will
+ * be chosen based on the type of the private key associated with the
+ * designated <i>Alias</i>. If the private key is a <code>DSA</code> one,
+ * the value for the signature algorithm will be <code>SHA1withDSA</code>.
+ * If on the other hand the private key is an <code>RSA</code> one, then
+ * the tool will use <code>MD5withRSA</code> as the signature algorithm.
+ * <p></dd>
+ *
+ * <dt>-file FILE_NAME</dt>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.
+ * <p></dd>
+ *
+ * <dt>-attributes</dt>
+ * <dd>Use this option to force the tool to encode a NULL DER value in the
+ * CSR as the value of the Attributes field.</dd>
+ * </dl>
+ */
+class CertReqCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(CertReqCmd.class.getName());
+ private static final String ATTRIBUTES_OPT = "attributes"; //$NON-NLS-1$
+ protected String _alias;
+ protected String _sigAlgorithm;
+ protected String _certReqFileName;
+ protected String _password;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ protected boolean nullAttributes;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /**
+ * @param algorithm the canonical name of the digital signature algorithm to
+ * use.
+ */
+ public void setSigalg(String algorithm)
+ {
+ this._sigAlgorithm = algorithm;
+ }
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certReqFileName = pathName;
+ }
+
+ /** @param password the (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ /**
+ * @param flag whether to use, or not, a <code>NULL</code> DER value for
+ * the certificate's Attributes field.
+ */
+ public void setAttributes(String flag)
+ {
+ this.nullAttributes = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(_certReqFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-certreq handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -sigalg=" + _sigAlgorithm); //$NON-NLS-1$
+ log.fine(" -file=" + _certReqFileName); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ log.fine(" -attributes=" + nullAttributes); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ InvalidKeyException, SignatureException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ // 1. get the key entry and certificate chain associated to alias
+ Key privateKey = getAliasPrivateKey();
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ // 2. get alias's DN and public key to use in the CSR
+ X509Certificate bottomCertificate = (X509Certificate) chain[0];
+ X500Principal aliasName = bottomCertificate.getIssuerX500Principal();
+ PublicKey publicKey = bottomCertificate.getPublicKey();
+
+ // 3. generate the CSR
+ setSignatureAlgorithmParam(_sigAlgorithm, privateKey);
+ byte[] derBytes = getCSR(aliasName, publicKey, (PrivateKey) privateKey);
+
+ // 4. encode it in base-64 and write it to outStream
+ String encoded = Base64.encode(derBytes, 72);
+ PrintWriter writer = new PrintWriter(outStream, true);
+ writer.println("-----BEGIN NEW CERTIFICATE REQUEST-----"); //$NON-NLS-1$
+ writer.println(encoded);
+ writer.println("-----END NEW CERTIFICATE REQUEST-----"); //$NON-NLS-1$
+
+ if (verbose)
+ {
+ if (! systemOut)
+ System.out.println(Messages.getFormattedString("CertReqCmd.27", //$NON-NLS-1$
+ _certReqFileName));
+ System.out.println(Messages.getString("CertReqCmd.28")); //$NON-NLS-1$
+ }
+
+ writer.close();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.CERTREQ_CMD, true);
+ result.setHeader(Messages.getString("CertReqCmd.25")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("CertReqCmd.24")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("CertReqCmd.23")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("CertReqCmd.22"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.21")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.SIGALG_OPT,
+ Messages.getString("CertReqCmd.20"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.19")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _sigAlgorithm = argument;
+ }
+ });
+ options.add(new Option(Main.FILE_OPT,
+ Messages.getString("CertReqCmd.18"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.17")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _certReqFileName = argument;
+ }
+ });
+ options.add(new Option(Main.KEYPASS_OPT,
+ Messages.getString("CertReqCmd.16"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.9")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _password = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("CertReqCmd.14"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.13")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("CertReqCmd.12"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.11")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("CertReqCmd.10"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.9")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("CertReqCmd.8"), //$NON-NLS-1$
+ Messages.getString("CertReqCmd.7")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("CertReqCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ options.add(new Option(ATTRIBUTES_OPT,
+ Messages.getString("CertReqCmd.5")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ nullAttributes = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * @param aliasName
+ * @param publicKey
+ * @param privateKey
+ * @return the DER encoded Certificate Signing Request.
+ * @throws IOException
+ * @throws InvalidKeyException
+ * @throws SignatureException
+ */
+ private byte[] getCSR(X500Principal aliasName, PublicKey publicKey,
+ PrivateKey privateKey)
+ throws IOException, InvalidKeyException, SignatureException
+ {
+ DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+ DERValue derSubject = new DERReader(aliasName.getEncoded()).read();
+ DERValue derSubjectPKInfo = new DERReader(publicKey.getEncoded()).read();
+ byte[] b = nullAttributes ? new byte[] { 0x05, 0x00 } : new byte[0];
+ DERValue derAttributes = new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0,
+ b.length, b, null);
+ ArrayList certRequestInfo = new ArrayList(4);
+ certRequestInfo.add(derVersion);
+ certRequestInfo.add(derSubject);
+ certRequestInfo.add(derSubjectPKInfo);
+ certRequestInfo.add(derAttributes);
+ DERValue derCertRequestInfo = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ certRequestInfo);
+
+ OID sigAlgorithmID = getSignatureAlgorithmOID();
+ DERValue derSigAlgorithmID = new DERValue(DER.OBJECT_IDENTIFIER,
+ sigAlgorithmID);
+ ArrayList sigAlgorithm = new ArrayList(2);
+ sigAlgorithm.add(derSigAlgorithmID);
+ if (! sigAlgorithmID.equals(Command.SHA1_WITH_DSA)) // it's an RSA-based
+ sigAlgorithm.add(new DERValue(DER.NULL, null));
+
+ sigAlgorithm.trimToSize();
+ DERValue derSignatureAlgorithm = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ sigAlgorithm);
+
+ signatureAlgorithm.initSign(privateKey);
+ signatureAlgorithm.update(derCertRequestInfo.getEncoded());
+ byte[] sigBytes = signatureAlgorithm.sign();
+ DERValue derSignature = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+
+ ArrayList csr = new ArrayList(3);
+ csr.add(derCertRequestInfo);
+ csr.add(derSignatureAlgorithm);
+ csr.add(derSignature);
+ DERValue derCSR = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, csr);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DERWriter.write(baos, derCSR);
+ byte[] result = baos.toByteArray();
+
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/Command.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/Command.java
new file mode 100644
index 000000000..050e75b37
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/Command.java
@@ -0,0 +1,1228 @@
+/* Command.java -- Abstract implementation of a keytool command handler
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.SystemProperties;
+import gnu.classpath.tools.common.CallbackUtil;
+import gnu.classpath.tools.common.ProviderUtil;
+import gnu.classpath.tools.common.SecurityProviderInfo;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.hash.MD5;
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.util.Util;
+import gnu.java.security.x509.X500DistinguishedName;
+
+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.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAKey;
+import java.security.interfaces.RSAKey;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.logging.Logger;
+import java.util.prefs.Preferences;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * A base class of the keytool command to facilitate implementation of concrete
+ * keytool Handlers.
+ */
+abstract class Command
+{
+ // Fields and constants -----------------------------------------------------
+
+ private static final Logger log = Logger.getLogger(Command.class.getName());
+ /** Default value for the ALIAS argument. */
+ private static final String DEFAULT_ALIAS = "mykey"; //$NON-NLS-1$
+ /** Default algorithm for key-pair generation. */
+ private static final String DEFAULT_KEY_ALGORITHM = "DSA"; //$NON-NLS-1$
+ /** Default DSA digital signature algorithm to use with DSA keys. */
+ private static final String DSA_SIGNATURE_ALGORITHM = "SHA1withDSA"; //$NON-NLS-1$
+ /** Default RSA digital signature algorithm to use with RSA keys. */
+ private static final String RSA_SIGNATURE_ALGORITHM = "MD5withRSA"; //$NON-NLS-1$
+ /** Default validity (in days) of newly generated certificates. */
+ private static final int DEFAULT_VALIDITY = 90;
+ /** OID of SHA1withDSA signature algorithm as stated in RFC-2459. */
+ protected static final OID SHA1_WITH_DSA = new OID("1.2.840.10040.4.3"); //$NON-NLS-1$
+ /** OID of MD2withRSA signature algorithm as stated in RFC-2459. */
+ private static final OID MD2_WITH_RSA = new OID("1.2.840.113549.1.1.2"); //$NON-NLS-1$
+ /** OID of MD5withRSA signature algorithm as stated in RFC-2459. */
+ private static final OID MD5_WITH_RSA = new OID("1.2.840.113549.1.1.4"); //$NON-NLS-1$
+ /** OID of SHA1withRSA signature algorithm as stated in RFC-2459. */
+ private static final OID SHA1_WITH_RSA = new OID("1.2.840.113549.1.1.5"); //$NON-NLS-1$
+ /** Number of milliseconds in one day. */
+ private static final long MILLIS_IN_A_DAY = 24 * 60 * 60 * 1000L;
+
+ /** The Alias to use. */
+ protected String alias;
+ /** The password characters protecting a Key Entry. */
+ protected char[] keyPasswordChars;
+ /** A security provider to add. */
+ protected Provider provider;
+ /** The key store type. */
+ protected String storeType;
+ /** The password characters protecting the key store. */
+ protected char[] storePasswordChars;
+ /** The key store URL. */
+ protected URL storeURL;
+ /** The input stream from the key store URL. */
+ protected InputStream storeStream;
+ /** The key store instance to use. */
+ protected KeyStore store;
+ /** The output stream the concrete handler will use. */
+ protected OutputStream outStream;
+ /** Whether we are printing to System.out. */
+ protected boolean systemOut;
+ /** The key-pair generation algorithm instance to use. */
+ protected KeyPairGenerator keyPairGenerator;
+ /** The digital signature algorithm instance to use. */
+ protected Signature signatureAlgorithm;
+ /** Validity period, in number of days, to use when generating certificates. */
+ protected int validityInDays;
+ /** The input stream the concrete handler will use. */
+ protected InputStream inStream;
+ /** Whether verbose output is required or not. */
+ protected boolean verbose;
+
+ /** MD5 hash to use when generating certificate fingerprints. */
+ private IMessageDigest md5 = new MD5();
+ /** SHA1 hash to use when generating certificate fingerprints. */
+ private IMessageDigest sha = new Sha160();
+ /** The new position of a user-defined provider if it is not already installed. */
+ private int providerNdx = -2;
+ /** The callback handler to use when needing to interact with user. */
+ private CallbackHandler handler;
+ /** The shutdown hook. */
+ private ShutdownHook shutdownThread;
+
+ // Constructor(s) -----------------------------------------------------------
+
+ protected Command()
+ {
+ super();
+ shutdownThread = new ShutdownHook();
+ Runtime.getRuntime().addShutdownHook(shutdownThread);
+ }
+
+ // Methods ------------------------------------------------------------------
+
+ /**
+ * A public method to allow using any keytool command handler programmatically
+ * by using a JavaBeans style of parameter(s) initialization. The user is
+ * assumed to have set individually the required options through their
+ * respective setters before invoking this method.
+ * <p>
+ * If an exception is encountered during the processing of the command, this
+ * implementation attempts to release any resources that may have been
+ * allocated at the time the exception occurs, before re-throwing that
+ * exception.
+ *
+ * @throws Exception if an exception occurs during the processing of this
+ * command. For a more comprehensive list of exceptions that may
+ * occur, see the documentation of the {@link #setup()} and
+ * {@link #start()} methods.
+ */
+ public void doCommand() throws Exception
+ {
+ try
+ {
+ setup();
+ start();
+ }
+ finally
+ {
+ teardown();
+ if (shutdownThread != null)
+ Runtime.getRuntime().removeShutdownHook(shutdownThread);
+ }
+ }
+
+ /**
+ * @param flag whether to use, or not, more verbose output while processing
+ * the command.
+ */
+ public void setVerbose(String flag)
+ {
+ this.verbose = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ /**
+ * Given a potential sub-array of options for this concrete handler, starting
+ * at position <code>startIndex + 1</code>, potentially followed by other
+ * commands and their options, this method sets up this concrete command
+ * handler with its own options and returns the index of the first unprocessed
+ * argument in the array.
+ * <p>
+ * The general contract of this method is that it is invoked with the
+ * <code>startIndex</code> argument pointing to the keyword argument that
+ * uniquelly identifies the command itself; e.g. <code>-genkey</code> or
+ * <code>-list</code>, etc...
+ *
+ * @param args an array of options for this handler and possibly other
+ * commands and their options.
+ * @return the remaining un-processed <code>args</code>.
+ */
+ String[] processArgs(String[] args)
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$
+ Parser cmdOptionsParser = getParser();
+ String[] result = cmdOptionsParser.parse(args);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "processArgs", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Initialize this concrete command handler for later invocation of the
+ * {@link #start()} or {@link #doCommand()} methods.
+ * <p>
+ * Handlers usually initialize their local variables and resources within the
+ * scope of this call.
+ *
+ * @throws IOException if an I/O related exception, such as opening an input
+ * stream, occurs during the execution of this method.
+ * @throws UnsupportedCallbackException if a requested callback handler
+ * implementation was not found, or was found but encountered an
+ * exception during its processing.
+ * @throws ClassNotFoundException if a designated security provider class was
+ * not found.
+ * @throws IllegalAccessException no 0-arguments constructor for the
+ * designated security provider class was found.
+ * @throws InstantiationException the designated security provider class is
+ * not instantiable.
+ * @throws KeyStoreException if an exception occurs during the instantiation
+ * of the KeyStore.
+ * @throws CertificateException if a certificate related exception, such as
+ * expiry, occurs during the loading of the KeyStore.
+ * @throws NoSuchAlgorithmException if no current security provider can
+ * provide a needed algorithm referenced by the KeyStore or one of
+ * its Key Entries or Certificates.
+ */
+ abstract void setup() throws Exception;
+
+ /**
+ * Do the real work this handler is supposed to do.
+ * <p>
+ * The code in this (abstract) class throws a <i>Not implemented yet</i>
+ * runtime exception. Concrete implementations MUST override this method.
+ *
+ * @throws CertificateException If no concrete implementation was found for a
+ * certificate Factory of a designated type. In this tool, the type
+ * is usually X.509 v1.
+ * @throws KeyStoreException if a keys-store related exception occurs; e.g.
+ * the key store has not been initialized.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws SignatureException if a digital signature related exception occurs.
+ * @throws InvalidKeyException if the genereated keys are invalid.
+ * @throws UnrecoverableKeyException if the password used to unlock a key in
+ * the key store was invalid.
+ * @throws NoSuchAlgorithmException if a concrete implementation of an
+ * algorithm used to store a Key Entry was not found at runtime.
+ * @throws UnsupportedCallbackException if a requested callback handler
+ * implementation was not found, or was found but encountered an
+ * exception during its processing.
+ */
+ void start() throws Exception
+ {
+ throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
+ }
+
+ /**
+ * Tear down the handler, releasing any resources which may have been
+ * allocated at setup time.
+ */
+ void teardown()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ if (storeStream != null)
+ try
+ {
+ storeStream.close();
+ }
+ catch (IOException ignored)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Exception while closing key store URL stream. Ignored: " //$NON-NLS-1$
+ + ignored);
+ }
+
+ if (outStream != null)
+ {
+ try
+ {
+ outStream.flush();
+ }
+ catch (IOException ignored)
+ {
+ }
+
+ if (! systemOut)
+ try
+ {
+ outStream.close();
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+
+ if (inStream != null)
+ try
+ {
+ inStream.close();
+ }
+ catch (IOException ignored)
+ {
+ }
+
+ if (providerNdx > 0)
+ ProviderUtil.removeProvider(provider.getName());
+
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ }
+
+ // parameter setup and validation methods -----------------------------------
+
+ /**
+ * @return a {@link Parser} that knows how to parse the concrete command's
+ * options.
+ */
+ abstract Parser getParser();
+
+ /**
+ * Convenience method to setup the key store given its type, its password, its
+ * location and portentially a specialized security provider.
+ * <p>
+ * Calls the method with the same name and 5 arguments passing
+ * <code>false</code> to the first argument implying that no attempt to
+ * create the keystore will be made if one was not found at the designated
+ * location.
+ *
+ * @param className the potentially null fully qualified class name of a
+ * security provider to add at runtime, if no installed provider is
+ * able to provide a key store implementation of the desired type.
+ * @param type the potentially null type of the key store to request from the
+ * key store factory.
+ * @param password the potentially null password protecting the key store.
+ * @param url the URL of the key store.
+ */
+ protected void setKeyStoreParams(String className, String type,
+ String password, String url)
+ throws IOException, UnsupportedCallbackException, KeyStoreException,
+ NoSuchAlgorithmException, CertificateException
+ {
+ setKeyStoreParams(false, className, type, password, url);
+ }
+
+ /**
+ * Convenience method to setup the key store given its type, its password, its
+ * location and portentially a specialized security provider.
+ *
+ * @param createIfNotFound if <code>true</code> then create the keystore if
+ * it was not found; otherwise do not.
+ * @param className the potentially null fully qualified class name of a
+ * security provider to add at runtime, if no installed provider is
+ * able to provide a key store implementation of the desired type.
+ * @param type the potentially null type of the key store to request from the
+ * key store factory.
+ * @param password the potentially null password protecting the key store.
+ * @param url the URL of the key store.
+ */
+ protected void setKeyStoreParams(boolean createIfNotFound, String className,
+ String type, String password, String url)
+ throws IOException, UnsupportedCallbackException, KeyStoreException,
+ NoSuchAlgorithmException, CertificateException
+ {
+ setProviderClassNameParam(className);
+ setKeystoreTypeParam(type);
+ setKeystoreURLParam(createIfNotFound, url, password);
+ }
+
+ /**
+ * Set a security provider class name to (install and) use for key store
+ * related operations.
+ *
+ * @param className the possibly null, fully qualified class name of a
+ * security provider to add, if it is not already installed, to the
+ * set of available providers.
+ */
+ private void setProviderClassNameParam(String className)
+ {
+ if (Configuration.DEBUG)
+ log.fine("setProviderClassNameParam(" + className + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (className != null && className.trim().length() > 0)
+ {
+ className = className.trim();
+ SecurityProviderInfo spi = ProviderUtil.addProvider(className);
+ provider = spi.getProvider();
+ if (provider == null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Was unable to add provider from class " + className);
+ }
+ providerNdx = spi.getPosition();
+ }
+ }
+
+ /**
+ * Set the type of key store to initialize, load and use.
+ *
+ * @param type the possibly null type of the key store. if this argument is
+ * <code>null</code>, or is an empty string, then this method sets
+ * the type of the key store to be the default value returned from
+ * the invocation of the {@link KeyStore#getDefaultType()} method.
+ * For GNU Classpath this is <i>gkr</i> which stands for the "Gnu
+ * KeyRing" specifications.
+ */
+ private void setKeystoreTypeParam(String type)
+ {
+ if (Configuration.DEBUG)
+ log.fine("setKeystoreTypeParam(" + type + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (type == null || type.trim().length() == 0)
+ storeType = KeyStore.getDefaultType();
+ else
+ storeType = type.trim();
+ }
+
+ /**
+ * Set the key password given a command line option argument. If no value was
+ * present on the command line then prompt the user to provide one.
+ *
+ * @param password a possibly null key password gleaned from the command line.
+ * @throws IOException if an I/O related exception occurs.
+ * @throws UnsupportedCallbackException if no concrete implementation of a
+ * password callback was found at runtime.
+ */
+ protected void setKeyPasswordParam(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ setKeyPasswordNoPrompt(password);
+ if (keyPasswordChars == null)
+ setKeyPasswordParam();
+ }
+
+ /**
+ * Set the Alias to use when associating Key Entries and Trusted Certificates
+ * in the current key store.
+ *
+ * @param name the possibly null alias to use. If this arfument is
+ * <code>null</code>, then a default value of <code>mykey</code>
+ * will be used instead.
+ */
+ protected void setAliasParam(String name)
+ {
+ alias = name == null ? DEFAULT_ALIAS : name.trim();
+ }
+
+ /**
+ * Set the key password given a command line option argument.
+ *
+ * @param password a possibly null key password gleaned from the command line.
+ */
+ protected void setKeyPasswordNoPrompt(String password)
+ {
+ if (password != null)
+ keyPasswordChars = password.toCharArray();
+ }
+
+ /**
+ * Prompt the user to provide a password to protect a Key Entry in the key
+ * store.
+ *
+ * @throws IOException if an I/O related exception occurs.
+ * @throws UnsupportedCallbackException if no concrete implementation of a
+ * password callback was found at runtime.
+ * @throws SecurityException if no password is available, even after prompting
+ * the user.
+ */
+ private void setKeyPasswordParam() throws IOException,
+ UnsupportedCallbackException
+ {
+ String prompt = Messages.getFormattedString("Command.21", alias); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(prompt, false);
+ getCallbackHandler().handle(new Callback[] { pcb });
+ keyPasswordChars = pcb.getPassword();
+ pcb.clearPassword();
+ if (keyPasswordChars == null)
+ throw new SecurityException(Messages.getString("Command.23")); //$NON-NLS-1$
+ }
+
+ private void setKeystorePasswordParam(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null)
+ storePasswordChars = password.toCharArray();
+ else // ask the user to provide one
+ {
+ String prompt = Messages.getString("Command.24"); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(prompt, false);
+ getCallbackHandler().handle(new Callback[] { pcb });
+ storePasswordChars = pcb.getPassword();
+ pcb.clearPassword();
+ }
+ }
+
+ /**
+ * Set the key store URL to use.
+ *
+ * @param createIfNotFound when <code>true</code> an attempt to create a
+ * keystore at the designated location will be made. If
+ * <code>false</code> then no file creation is carried out, which
+ * may cause an exception to be thrown later.
+ * @param url the full, or partial, URL to the keystore location.
+ * @param password an eventually null string to use when loading the keystore.
+ * @throws IOException
+ * @throws KeyStoreException
+ * @throws UnsupportedCallbackException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ */
+ private void setKeystoreURLParam(boolean createIfNotFound, String url,
+ String password) throws IOException,
+ KeyStoreException, UnsupportedCallbackException, NoSuchAlgorithmException,
+ CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.fine("setKeystoreURLParam(" + url + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (url == null || url.trim().length() == 0)
+ {
+ String userHome = SystemProperties.getProperty("user.home"); //$NON-NLS-1$
+ if (userHome == null || userHome.trim().length() == 0)
+ throw new InvalidParameterException(Messages.getString("Command.36")); //$NON-NLS-1$
+
+ url = userHome.trim() + "/.keystore"; //$NON-NLS-1$
+ // if it does not exist create it if required
+ if (createIfNotFound)
+ new File(url).createNewFile();
+ url = "file:" + url; //$NON-NLS-1$
+ }
+ else
+ {
+ url = url.trim();
+ if (url.indexOf(":") == -1) // if it does not exist create it //$NON-NLS-1$
+ {
+ if (createIfNotFound)
+ new File(url).createNewFile();
+ }
+ url = "file:" + url; //$NON-NLS-1$
+ }
+
+ boolean newKeyStore = false;
+ storeURL = new URL(url);
+ storeStream = storeURL.openStream();
+ if (storeStream.available() == 0)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Store is empty. Will use <null> when loading, to create it"); //$NON-NLS-1$
+ newKeyStore = true;
+ }
+
+ try
+ {
+ store = KeyStore.getInstance(storeType);
+ }
+ catch (KeyStoreException x)
+ {
+ if (provider != null)
+ throw x;
+
+ if (Configuration.DEBUG)
+ log.fine("Exception while getting key store with default provider(s)." //$NON-NLS-1$
+ + " Will prompt user for another provider and continue"); //$NON-NLS-1$
+ String prompt = Messages.getString("Command.40"); //$NON-NLS-1$
+ NameCallback ncb = new NameCallback(prompt);
+ getCallbackHandler().handle(new Callback[] { ncb });
+ String className = ncb.getName();
+ setProviderClassNameParam(className); // we may have a Provider
+ if (provider == null)
+ {
+ x.fillInStackTrace();
+ throw x;
+ }
+ // try again
+ store = KeyStore.getInstance(storeType, provider);
+ }
+
+ setKeystorePasswordParam(password);
+
+ // now we have a KeyStore instance. load it
+ // KeyStore public API claims: "...In order to create an empty keystore,
+ // you pass null as the InputStream argument to the load method.
+ if (newKeyStore)
+ store.load(null, storePasswordChars);
+ else
+ store.load(storeStream, storePasswordChars);
+
+ // close the stream
+ try
+ {
+ storeStream.close();
+ storeStream = null;
+ }
+ catch (IOException x)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Exception while closing the key store input stream: " + x //$NON-NLS-1$
+ + ". Ignore"); //$NON-NLS-1$
+ }
+ }
+
+ protected void setOutputStreamParam(String fileName) throws SecurityException,
+ IOException
+ {
+ if (fileName == null || fileName.trim().length() == 0)
+ {
+ outStream = System.out;
+ systemOut = true;
+ }
+ else
+ {
+ fileName = fileName.trim();
+ File outFile = new File(fileName);
+ if (! outFile.exists())
+ {
+ boolean ok = outFile.createNewFile();
+ if (!ok)
+ throw new InvalidParameterException(Messages.getFormattedString("Command.19", //$NON-NLS-1$
+ fileName));
+ }
+ else
+ {
+ if (! outFile.isFile())
+ throw new InvalidParameterException(Messages.getFormattedString("Command.42", //$NON-NLS-1$
+ fileName));
+ if (! outFile.canWrite())
+ throw new InvalidParameterException(Messages.getFormattedString("Command.44", //$NON-NLS-1$
+ fileName));
+ }
+ outStream = new FileOutputStream(outFile);
+ }
+ }
+
+ protected void setInputStreamParam(String fileName)
+ throws FileNotFoundException
+ {
+ if (fileName == null || fileName.trim().length() == 0)
+ inStream = System.in;
+ else
+ {
+ fileName = fileName.trim();
+ File inFile = new File(fileName);
+ if (! (inFile.exists() && inFile.isFile() && inFile.canRead()))
+ throw new InvalidParameterException(Messages.getFormattedString("Command.46", //$NON-NLS-1$
+ fileName));
+ inStream = new FileInputStream(inFile);
+ }
+ }
+
+ /**
+ * Set both the key-pair generation algorithm, and the digital signature
+ * algorithm instances to use when generating new entries.
+ *
+ * @param kpAlg the possibly null name of a key-pair generator algorithm.
+ * if this argument is <code>null</code> or is an empty string, the
+ * "DSS" algorithm will be used.
+ * @param sigAlg the possibly null name of a digital signature algorithm.
+ * If this argument is <code>null</code> or is an empty string, this
+ * method uses the "SHA1withDSA" (Digital Signature Standard, a.k.a.
+ * DSA, with the Secure Hash Algorithm function) as the default
+ * algorithm if, and only if, the key-pair generation algorithm ends
+ * up being "DSS"; otherwise, if the key-pair generation algorithm
+ * was "RSA", then the "MD5withRSA" signature algorithm will be used.
+ * If the key-pair generation algorithm is neither "DSS" (or its
+ * alias "DSA"), nor is it "RSA", then an exception is thrown.
+ * @throws NoSuchAlgorithmException if no concrete implementation of the
+ * designated algorithm is available.
+ */
+ protected void setAlgorithmParams(String kpAlg, String sigAlg)
+ throws NoSuchAlgorithmException
+ {
+ if (kpAlg == null || kpAlg.trim().length() == 0)
+ kpAlg = DEFAULT_KEY_ALGORITHM;
+ else
+ kpAlg = kpAlg.trim().toLowerCase();
+
+ keyPairGenerator = KeyPairGenerator.getInstance(kpAlg);
+
+ if (sigAlg == null || sigAlg.trim().length() == 0)
+ if (kpAlg.equalsIgnoreCase(Registry.DSS_KPG)
+ || kpAlg.equalsIgnoreCase(Registry.DSA_KPG))
+ sigAlg = DSA_SIGNATURE_ALGORITHM;
+ else if (kpAlg.equalsIgnoreCase(Registry.RSA_KPG))
+ sigAlg = RSA_SIGNATURE_ALGORITHM;
+ else
+ throw new IllegalArgumentException(
+ Messages.getFormattedString("Command.20", //$NON-NLS-1$
+ new String[] { sigAlg, kpAlg }));
+ else
+ sigAlg = sigAlg.trim().toLowerCase();
+
+ signatureAlgorithm = Signature.getInstance(sigAlg);
+ }
+
+ /**
+ * Set the signature algorithm to use when digitally signing private keys,
+ * certificates, etc...
+ * <p>
+ * If the designated algorithm name is <code>null</code> or is an empty
+ * string, this method checks the private key (the second argument) and based
+ * on its type decides which algorithm to use. The keytool public
+ * specification states that if the private key is a DSA key, then the
+ * signature algorithm will be <code>SHA1withDSA</code>, otherwise if it is
+ * an RSA private key, then the signature algorithm will be
+ * <code>MD5withRSA</code>. If the private key is neither a private DSA nor
+ * a private RSA key, then this method throws an
+ * {@link IllegalArgumentException}.
+ *
+ * @param algorithm the possibly null name of a digital signature algorithm.
+ * @param privateKey an instance of a private key to use as a fal-back option
+ * when <code>algorithm</code> is invalid.
+ * @throws NoSuchAlgorithmException if no concrete implementation of the
+ * designated, or default, signature algorithm is available.
+ */
+ protected void setSignatureAlgorithmParam(String algorithm, Key privateKey)
+ throws NoSuchAlgorithmException
+ {
+ if (algorithm == null || algorithm.trim().length() == 0)
+ if (privateKey instanceof DSAKey)
+ algorithm = DSA_SIGNATURE_ALGORITHM;
+ else if (privateKey instanceof RSAKey)
+ algorithm = RSA_SIGNATURE_ALGORITHM;
+ else
+ throw new InvalidParameterException(Messages.getString("Command.48")); //$NON-NLS-1$
+ else
+ algorithm = algorithm.trim();
+
+ signatureAlgorithm = Signature.getInstance(algorithm);
+ }
+
+ /**
+ * Set the validity period, in number of days, to use when issuing new
+ * certificates.
+ *
+ * @param days the number of days, as a string, the generated certificate will
+ * be valid for, starting from today's date. if this argument is
+ * <code>null</code>, a default value of <code>90</code> days
+ * will be used.
+ * @throws NumberFormatException if the designated string is not a decimal
+ * integer.
+ * @throws InvalidParameterException if the integer value of the non-null
+ * string is not greater than zero.
+ */
+ protected void setValidityParam(String days)
+ {
+ if (days == null || days.trim().length() == 0)
+ validityInDays = DEFAULT_VALIDITY;
+ else
+ {
+ days = days.trim();
+ validityInDays = Integer.parseInt(days);
+ if (validityInDays < 1)
+ throw new InvalidParameterException(Messages.getString("Command.51")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * RFC-2459 (http://rfc.net/rfc2459.html) fully describes the structure and
+ * semantics of X.509 certificates. The ASN.1 structures below are gleaned
+ * from that reference.
+ *
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING
+ * }
+ *
+ * TBSCertificate ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo
+ * }
+ *
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ *
+ * CertificateSerialNumber ::= INTEGER
+ *
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time
+ * }
+ *
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime
+ * }
+ *
+ * UniqueIdentifier ::= BIT STRING
+ *
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ * </pre>
+ *
+ * @param distinguishedName the X.500 Distinguished Name to use as both the
+ * Issuer and Subject of the self-signed certificate to generate.
+ * @param publicKey the public key of the issuer/subject.
+ * @param privateKey the private key of the issuer/signer.
+ * @return the DER encoded form of a self-signed X.509 v1 certificate.
+ * @throws IOException If an I/O related exception occurs during the process.
+ * @throws SignatureException If a digital signature related exception occurs.
+ * @throws InvalidKeyException if the designated private key is invalid.
+ * @throws InvalidParameterException if the concrete signature algorithm does
+ * not know its name, no OID is known/supported for that name, or we
+ * were unable to match the name to a known string for which we can
+ * use a standard OID.
+ */
+ protected byte[] getSelfSignedCertificate(X500DistinguishedName distinguishedName,
+ PublicKey publicKey,
+ PrivateKey privateKey)
+ throws IOException, SignatureException, InvalidKeyException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getSelfSignedCertificate", //$NON-NLS-1$
+ new Object[] { distinguishedName, publicKey, privateKey });
+ byte[] versionBytes = new DERValue(DER.INTEGER, BigInteger.ZERO).getEncoded();
+ DERValue derVersion = new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0,
+ versionBytes.length, versionBytes, null);
+
+ // NOTE (rsn): the next 3 lines should be atomic but they're not.
+ Preferences prefs = Preferences.systemNodeForPackage(this.getClass());
+ int lastSerialNumber = prefs.getInt(Main.LAST_SERIAL_NUMBER, 0) + 1;
+ prefs.putInt(Main.LAST_SERIAL_NUMBER, lastSerialNumber);
+ DERValue derSerialNumber = new DERValue(DER.INTEGER,
+ BigInteger.valueOf(lastSerialNumber));
+
+ OID signatureID = getSignatureAlgorithmOID();
+ DERValue derSignatureID = new DERValue(DER.OBJECT_IDENTIFIER, signatureID);
+ ArrayList signature = new ArrayList(1);
+ signature.add(derSignatureID);
+ // rfc-2459 states the following:
+ //
+ // for the DSA signature:
+ // ...Where the id-dsa-with-sha1 algorithm identifier appears as the
+ // algorithm field in an AlgorithmIdentifier, the encoding shall omit
+ // the parameters field. That is, the AlgorithmIdentifier shall be a
+ // SEQUENCE of one component - the OBJECT IDENTIFIER id-dsa-with-sha1.
+ //
+ // for RSA signatures:
+ // ...When any of these three OIDs (i.e. xxxWithRSAEncryption) appears
+ // within the ASN.1 type AlgorithmIdentifier, the parameters component of
+ // that type shall be the ASN.1 type NULL.
+ if (! signatureID.equals(SHA1_WITH_DSA))
+ signature.add(new DERValue(DER.NULL, null));
+
+ DERValue derSignature = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ signature);
+
+ DERValue derIssuer = new DERReader(distinguishedName.getDer()).read();
+
+ long notBefore = System.currentTimeMillis();
+ long notAfter = notBefore + validityInDays * MILLIS_IN_A_DAY;
+
+ ArrayList validity = new ArrayList(2);
+ validity.add(new DERValue(DER.UTC_TIME, new Date(notBefore)));
+ validity.add(new DERValue(DER.UTC_TIME, new Date(notAfter)));
+ DERValue derValidity = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ validity);
+
+ // for a self-signed certificate subject and issuer are identical
+ DERValue derSubject = derIssuer;
+
+ DERValue derSubjectPublicKeyInfo = new DERReader(publicKey.getEncoded()).read();
+
+ ArrayList tbsCertificate = new ArrayList(7);
+ tbsCertificate.add(derVersion);
+ tbsCertificate.add(derSerialNumber);
+ tbsCertificate.add(derSignature);
+ tbsCertificate.add(derIssuer);
+ tbsCertificate.add(derValidity);
+ tbsCertificate.add(derSubject);
+ tbsCertificate.add(derSubjectPublicKeyInfo);
+ DERValue derTBSCertificate = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ tbsCertificate);
+
+ // The 'signature' field MUST contain the same algorithm identifier as the
+ // 'signatureAlgorithm' field in the sequence Certificate.
+ DERValue derSignatureAlgorithm = derSignature;
+
+ signatureAlgorithm.initSign(privateKey);
+ signatureAlgorithm.update(derTBSCertificate.getEncoded());
+ byte[] sigBytes = signatureAlgorithm.sign();
+ DERValue derSignatureValue = new DERValue(DER.BIT_STRING,
+ new BitString(sigBytes));
+
+ ArrayList certificate = new ArrayList(3);
+ certificate.add(derTBSCertificate);
+ certificate.add(derSignatureAlgorithm);
+ certificate.add(derSignatureValue);
+ DERValue derCertificate = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ certificate);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DERWriter.write(baos, derCertificate);
+ byte[] result = baos.toByteArray();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getSelfSignedCertificate"); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * This method attempts to find, and return, an OID representing the digital
+ * signature algorithm used to sign the certificate. The OIDs returned are
+ * those described in RFC-2459. They are listed here for the sake of
+ * completness.
+ *
+ * <pre>
+ * id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) x9-57 (10040) x9cm(4) 3
+ * }
+ *
+ * md2WithRSAEncryption OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 2
+ * }
+ *
+ * md5WithRSAEncryption OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 4
+ * }
+ *
+ * sha-1WithRSAEncryption OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 5
+ * }
+ * </pre>
+ *
+ * <b>IMPORTANT</b>: This method checks the signature algorithm name against
+ * (a) The GNU algorithm implementation's name, and (b) publicly referenced
+ * names of the same algorithm. In other words this search is not
+ * comprehensive and may fail for uncommon names of the same algorithms.
+ *
+ * @return the OID of the signature algorithm in use.
+ * @throws InvalidParameterException if the concrete signature algorithm does
+ * not know its name, no OID is known/supported for that name, or we
+ * were unable to match the name to a known string for which we can
+ * return an OID.
+ */
+ protected OID getSignatureAlgorithmOID()
+ {
+ String algorithm = signatureAlgorithm.getAlgorithm();
+ // if we already have a non-null signature then the name was valid. the
+ // only case where algorithm is invalid would be if the implementation is
+ // flawed. check anyway
+ if (algorithm == null || algorithm.trim().length() == 0)
+ throw new InvalidParameterException(Messages.getString("Command.52")); //$NON-NLS-1$
+
+ algorithm = algorithm.trim();
+ if (algorithm.equalsIgnoreCase(Registry.DSS_SIG)
+ || algorithm.equalsIgnoreCase("SHA1withDSA")) //$NON-NLS-1$
+ return SHA1_WITH_DSA;
+
+ if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
+ + Registry.MD2_HASH)
+ || algorithm.equalsIgnoreCase("MD2withRSA")) //$NON-NLS-1$
+ return MD2_WITH_RSA;
+
+ if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
+ + Registry.MD5_HASH)
+ || algorithm.equalsIgnoreCase("MD5withRSA") //$NON-NLS-1$
+ || algorithm.equalsIgnoreCase("rsa")) //$NON-NLS-1$
+ return MD5_WITH_RSA;
+
+ if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
+ + Registry.SHA160_HASH)
+ || algorithm.equalsIgnoreCase("SHA1withRSA")) //$NON-NLS-1$
+ return SHA1_WITH_RSA;
+
+ throw new InvalidParameterException(Messages.getFormattedString("Command.60", //$NON-NLS-1$
+ algorithm));
+ }
+
+ /**
+ * Saves the key store using the designated password. This operation is called
+ * by handlers if/when the key store password has changed, or amendements have
+ * been made to the contents of the store; e.g. addition of a new Key Entry or
+ * a Trusted Certificate.
+ *
+ * @param password the password protecting the key store.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws CertificateException if any of the certificates in the current key
+ * store could not be persisted.
+ * @throws NoSuchAlgorithmException if a required data integrity algorithm
+ * implementation was not found.
+ * @throws KeyStoreException if the key store has not been loaded previously.
+ */
+ protected void saveKeyStore(char[] password) throws IOException,
+ KeyStoreException, NoSuchAlgorithmException, CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "saveKeyStore"); //$NON-NLS-1$
+ URLConnection con = storeURL.openConnection();
+ con.setDoOutput(true);
+ con.setUseCaches(false);
+ OutputStream out = con.getOutputStream();
+ if (verbose)
+ System.out.println(Messages.getFormattedString("Command.63", storeURL.getPath())); //$NON-NLS-1$
+
+ store.store(out, password);
+ out.flush();
+ out.close();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "saveKeyStore"); //$NON-NLS-1$
+ }
+
+ /**
+ * Convenience method. Calls the method with the same name passing it the
+ * same password characters used to initially load the key-store.
+ *
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws KeyStoreException if the key store has not been loaded previously.
+ * @throws NoSuchAlgorithmException if a required data integrity algorithm
+ * implementation was not found.
+ * @throws CertificateException if any of the certificates in the current key
+ * store could not be persisted.
+ */
+ protected void saveKeyStore() throws IOException, KeyStoreException,
+ NoSuchAlgorithmException, CertificateException
+ {
+ saveKeyStore(storePasswordChars);
+ }
+
+ /**
+ * Prints a human-readable form of the designated certificate to a designated
+ * {@link PrintWriter}.
+ *
+ * @param certificate the certificate to process.
+ * @param writer where to print it.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form <code>certificate</code>.
+ */
+ protected void printVerbose(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ X509Certificate x509 = (X509Certificate) certificate;
+ writer.println(Messages.getFormattedString("Command.66", x509.getSubjectDN())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.67", x509.getIssuerDN())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.68", x509.getSerialNumber())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.69", x509.getNotBefore())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.70", x509.getNotAfter())); //$NON-NLS-1$
+ writer.println(Messages.getString("Command.71")); //$NON-NLS-1$
+ byte[] derBytes = certificate.getEncoded();
+ writer.println(Messages.getFormattedString("Command.72", digest(md5, derBytes))); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.73", digest(sha, derBytes))); //$NON-NLS-1$
+ }
+
+ /**
+ * Convenience method. Prints a human-readable form of the designated
+ * certificate to <code>System.out</code>.
+ *
+ * @param certificate the certificate to process.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form <code>certificate</code>.
+ */
+ protected void printVerbose(Certificate certificate)
+ throws CertificateEncodingException
+ {
+ printVerbose(certificate, new PrintWriter(System.out, true));
+ }
+
+ /**
+ * Digest the designated contents with MD5 and return a string representation
+ * suitable for use as a fingerprint; i.e. sequence of hexadecimal pairs of
+ * characters separated by a colon.
+ *
+ * @param contents the non-null contents to digest.
+ * @return a sequence of hexadecimal pairs of characters separated by colons.
+ */
+ protected String digestWithMD5(byte[] contents)
+ {
+ return digest(md5, contents);
+ }
+
+ private String digest(IMessageDigest hash, byte[] encoded)
+ {
+ hash.update(encoded);
+ byte[] b = hash.digest();
+ StringBuilder sb = new StringBuilder().append(Util.toString(b, 0, 1));
+ for (int i = 1; i < b.length; i++)
+ sb.append(":").append(Util.toString(b, i, 1)); //$NON-NLS-1$
+
+ String result = sb.toString();
+ return result;
+ }
+
+ /**
+ * Ensure that the currently set Alias is contained in the currently set key
+ * store; otherwise throw an exception.
+ *
+ * @throws KeyStoreException if the keystore has not been loaded.
+ * @throws IllegalArgumentException if the currently set alias is not known to
+ * the currently set key store.
+ */
+ protected void ensureStoreContainsAlias() throws KeyStoreException
+ {
+ if (! store.containsAlias(alias))
+ throw new IllegalArgumentException(Messages.getFormattedString("Command.75", //$NON-NLS-1$
+ alias));
+ }
+
+ /**
+ * Ensure that the currently set Alias is associated with a Key Entry in the
+ * currently set key store; otherwise throw an exception.
+ *
+ * @throws KeyStoreException if the keystore has not been loaded.
+ * @throws SecurityException if the currently set alias is not a Key Entry in
+ * the currently set key store.
+ */
+ protected void ensureAliasIsKeyEntry() throws KeyStoreException
+ {
+ if (! store.isKeyEntry(alias))
+ throw new SecurityException(Messages.getFormattedString("Command.77", //$NON-NLS-1$
+ alias));
+ }
+
+ protected Key getAliasPrivateKey() throws KeyStoreException,
+ NoSuchAlgorithmException, IOException, UnsupportedCallbackException,
+ UnrecoverableKeyException
+ {
+ ensureAliasIsKeyEntry();
+ Key result;
+ if (keyPasswordChars == null)
+ try
+ {
+ result = store.getKey(alias, storePasswordChars);
+ // it worked. assign to keyPasswordChars for later use
+ keyPasswordChars = storePasswordChars;
+ }
+ catch (UnrecoverableKeyException x)
+ {
+ // prompt the user to provide one
+ setKeyPasswordParam();
+ result = store.getKey(alias, keyPasswordChars);
+ }
+ else
+ result = store.getKey(alias, keyPasswordChars);
+
+ return result;
+ }
+
+ /**
+ * Return a CallbackHandler which uses the Console (System.in and System.out)
+ * for interacting with the user.
+ * <p>
+ * This method first finds all currently installed security providers capable
+ * of providing such service and then in turn attempts to instantiate the
+ * handler from those providers. As soon as one provider returns a non-null
+ * instance of the callback handler, the search stops and that instance is
+ * set to be used from now on.
+ * <p>
+ * If no installed providers were found, this method falls back on the GNU
+ * provider, by-passing the Security search mechanism. The default console
+ * callback handler implementation is
+ * {@link gnu.javax.security.auth.callback.ConsoleCallbackHandler}.
+ *
+ * @return a console-based {@link CallbackHandler}.
+ */
+ protected CallbackHandler getCallbackHandler()
+ {
+ if (handler == null)
+ handler = CallbackUtil.getConsoleHandler();
+
+ return handler;
+ }
+
+ // Inner class(es) ==========================================================
+
+ private class ShutdownHook
+ extends Thread
+ {
+ public void run()
+ {
+ teardown();
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/DeleteCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/DeleteCmd.java
new file mode 100644
index 000000000..5a9cbfd1f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/DeleteCmd.java
@@ -0,0 +1,280 @@
+/* DeleteCmd.java -- The delete command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-delete</b> keytool command handler is used to delete from the key
+ * store the entry associated with a designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class DeleteCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(DeleteCmd.class.getName());
+ protected String _alias;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setTheAlias(_alias);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-delete handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ CertificateException, IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ ensureStoreContainsAlias();
+ store.deleteEntry(alias);
+ saveKeyStore();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.DELETE_CMD, true);
+ result.setHeader(Messages.getString("DeleteCmd.18")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("DeleteCmd.17")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("DeleteCmd.16")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("DeleteCmd.15"), //$NON-NLS-1$
+ Messages.getString("DeleteCmd.14")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("DeleteCmd.13"), //$NON-NLS-1$
+ Messages.getString("DeleteCmd.12")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("DeleteCmd.11"), //$NON-NLS-1$
+ Messages.getString("DeleteCmd.10")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("DeleteCmd.9"), //$NON-NLS-1$
+ Messages.getString("DeleteCmd.8")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("DeleteCmd.7"), //$NON-NLS-1$
+ Messages.getString("DeleteCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("DeleteCmd.5")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Set the alias to delete from the key store.
+ * <p>
+ * Unlike in other keytool handlers, the default value (<i>mykey</i>) for the
+ * Alias is not used. Instead, if an alias was not found on the command line,
+ * the user is prompted to enter one.
+ *
+ * @param anAlias a possibly null Alias gleaned from the command line.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws UnsupportedCallbackException if no implementation of a password
+ * callback handler was found.
+ */
+ private void setTheAlias(String anAlias) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (anAlias == null || anAlias.trim().length() == 0)
+ {
+ String prompt = Messages.getString("DeleteCmd.19"); //$NON-NLS-1$
+ NameCallback ncb = new NameCallback(prompt);
+ getCallbackHandler().handle(new Callback[] { ncb });
+ anAlias = ncb.getName();
+ if (anAlias == null || anAlias.trim().length() == 0)
+ throw new SecurityException(Messages.getString("DeleteCmd.20")); //$NON-NLS-1$
+ }
+ alias = anAlias.trim();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/ExportCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/ExportCmd.java
new file mode 100644
index 000000000..035fbab6a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/ExportCmd.java
@@ -0,0 +1,328 @@
+/* ExportCmd.java -- The export command handler of the keytool
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.util.Base64;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.logging.Logger;
+
+/**
+ * The <b>-export</b> keytool command handler is used to read the certificate
+ * associated with a designated alias from the key store, and write it to a
+ * designated file.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the file where the certificate will be
+ * exported to. If omitted, STDOUT will be used instead.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-rfc</dt>
+ * <dd>Use RFC-1421 specifications when encoding the output.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Output the certificate in binary DER encoding. This is the default
+ * output format of the command if neither <code>-rfc</code> nor
+ * <code>-v</code> options were detected on the command line. If both this
+ * option and the <code>-rfc</code> option are detected on the command
+ * line, the tool will opt for the RFC-1421 style encoding.</dd>
+ * </dl>
+ */
+class ExportCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(ExportCmd.class.getName());
+ protected String _alias;
+ protected String _certFileName;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ protected boolean rfc;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certFileName = pathName;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ /**
+ * @param flag whether to use, or not, RFC-1421 format when exporting the
+ * certificate(s).
+ */
+ public void setRfc(String flag)
+ {
+ this.rfc = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(_certFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-export handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -file=" + _certFileName); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -rfc=" + rfc); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, CertificateEncodingException,
+ IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ ensureStoreContainsAlias();
+ Certificate certificate;
+ if (store.isCertificateEntry(alias))
+ {
+ if (Configuration.DEBUG)
+ log.fine("Alias [" + alias + "] is a trusted certificate"); //$NON-NLS-1$ //$NON-NLS-2$
+ certificate = store.getCertificate(alias);
+ }
+ else
+ {
+ if (Configuration.DEBUG)
+ log.fine("Alias [" + alias + "] is a key entry"); //$NON-NLS-1$ //$NON-NLS-2$
+ Certificate[] chain = store.getCertificateChain(alias);
+ certificate = chain[0];
+ }
+
+ byte[] derBytes = certificate.getEncoded();
+ if (rfc)
+ {
+ String encoded = Base64.encode(derBytes, 72);
+ PrintWriter pw = new PrintWriter(outStream, true);
+ pw.println("-----BEGIN CERTIFICATE-----"); //$NON-NLS-1$
+ pw.println(encoded);
+ pw.println("-----END CERTIFICATE-----"); //$NON-NLS-1$
+ }
+ else
+ outStream.write(derBytes);
+
+ // stream is closed in Command.teardown()
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.EXPORT_CMD, true);
+ result.setHeader(Messages.getString("ExportCmd.17")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("ExportCmd.18")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("ExportCmd.19")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("ExportCmd.20"), //$NON-NLS-1$
+ Messages.getString("ExportCmd.21")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.FILE_OPT,
+ Messages.getString("ExportCmd.22"), //$NON-NLS-1$
+ Messages.getString("ExportCmd.23")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _certFileName = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("ExportCmd.24"), //$NON-NLS-1$
+ Messages.getString("ExportCmd.25")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("ExportCmd.26"), //$NON-NLS-1$
+ Messages.getString("ExportCmd.27")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("ExportCmd.28"), //$NON-NLS-1$
+ Messages.getString("ExportCmd.29")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("ExportCmd.30"), //$NON-NLS-1$
+ Messages.getString("ExportCmd.31")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.RFC_OPT,
+ Messages.getString("ExportCmd.32")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ rfc = true;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("ExportCmd.33")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/GenKeyCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/GenKeyCmd.java
new file mode 100644
index 000000000..b892ca794
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/GenKeyCmd.java
@@ -0,0 +1,602 @@
+/* GenKeyCmd.java -- The genkey command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.security.util.Util;
+import gnu.java.security.x509.X500DistinguishedName;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-genkey</b> keytool command handler is used to generate a key pair (a
+ * public, and associated private keys). It then generates a self-signed X509 v1
+ * certificate (authenticating the public key) and stores this certificate and
+ * the private key in the key store associating both to a designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-keyalg ALGORITHM</dt>
+ * <dd>Use this option to specify the canonical name of the key-pair
+ * generation algorithm. The default value for this option is
+ * <code>DSS</code> (a synonym for the Digital Signature Algorithm also
+ * known as <code>DSA</code>).
+ * <p></dd>
+ *
+ * <dt>-keysize KEY_SIZE</dt>
+ * <dd>Use this option to specify the number of bits of the shared modulus
+ * (for both the public and private keys) to use when generating new keys.
+ * A default value of <code>1024</code> will be used if this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-sigalg ALGORITHM</dt>
+ * <dd>The canonical name of the digital signature algorithm to use for
+ * signing certificates. If this option is omitted, a default value will be
+ * chosen based on the type of the key-pair; i.e. the algorithm that ends
+ * up being used by the <code>-keyalg</code> option. If the key-pair
+ * generation algorithm is <code>DSA</code>, the value for the signature
+ * algorithm will be <code>SHA1withDSA</code>. If on the other hand the
+ * key-pair generation algorithm is <code>RSA</code>, then the tool will
+ * use <code>MD5withRSA</code> as the signature algorithm.
+ * <p></dd>
+ *
+ * <dt>-dname NAME</dt>
+ * <dd>This a mandatory value for this command. If this option is omitted
+ * the tool will prompt you to enter a <i>Distinguished Name</i> to use as
+ * both the <i>Owner</i> and <i>Issuer</i> of the generated self-signed
+ * certificate.
+ * <p>
+ * The syntax of a valid value for this option MUST follow RFC-2253
+ * specifications. Namely the following components (with their accepted
+ * meaning) will be recognized. Note that the component name is case-
+ * insensitive:
+ * <dl>
+ * <dt>CN</dt>
+ * <dd>The Common Name; e.g. "host.domain.com"</dd>
+ *
+ * <dt>OU</dt>
+ * <dd>The Organizational Unit; e.g. "IT Department"</dd>
+ *
+ * <dt>O</dt>
+ * <dd>The Organization Name; e.g. "The Sample Company"</dd>
+ *
+ * <dt>L</dt>
+ * <dd>The Locality Name; e.g. "Sydney"</dd>
+ *
+ * <dt>ST</dt>
+ * <dd>The State Name; e.g. "New South Wales"</dd>
+ *
+ * <dt>C</dt>
+ * <dd>The 2-letter Country identifier; e.g. "AU"</dd>
+ * </dl>
+ * <p>
+ * When specified with a <code>-dname</code> option, each pair of component
+ * / value will be separated from the other with a comma. Each component
+ * and value pair MUST be separated by an equal sign. For example, the
+ * following is a valid DN value:
+ * <pre>
+ * CN=host.domain.com, O=The Sample Company, L=Sydney, ST=NSW, C=AU
+ * </pre>
+ * If this option is omitted, the tool will prompt you to enter the
+ * information through the console.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * protect the newly created Key Entry.
+ * <p>
+ * If this option is omitted, you will be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-validity DAY_COUNT</dt>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class GenKeyCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(GenKeyCmd.class.getName());
+ /** Default key size in bits. */
+ private static final int DEFAULT_KEY_SIZE = 1024;
+
+ protected String _alias;
+ protected String _keyAlgorithm;
+ protected String _keySizeStr;
+ protected String _sigAlgorithm;
+ protected String _dName;
+ protected String _password;
+ protected String _validityStr;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ private int keySize;
+ private X500DistinguishedName distinguishedName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param algorithm the canonical name of the key-pair algorithm to use. */
+ public void setKeyalg(String algorithm)
+ {
+ this._keyAlgorithm = algorithm;
+ }
+
+ /**
+ * @param bits the string representation of the number of bits (a decimal
+ * positive integer) the modulus of the generated keys (private and
+ * public) should have.
+ */
+ public void setKeysize(String bits)
+ {
+ this._validityStr = bits;
+ }
+
+ /**
+ * @param algorithm the canonical name of the digital signature algorithm to
+ * use.
+ */
+ public void setSigalg(String algorithm)
+ {
+ this._sigAlgorithm = algorithm;
+ }
+
+ /** @param name the distiniguished name to use. */
+ public void setDname(String name)
+ {
+ this._dName = name;
+ }
+
+ /** @param password the (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /**
+ * @param days the string representation of the number of days (a decimal,
+ * positive integer) to assign to the generated certificate.
+ */
+ public void setValidity(String days)
+ {
+ this._validityStr = days;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(true, _providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordParam(_password);
+ setAlgorithmParams(_keyAlgorithm, _sigAlgorithm);
+ setKeySize(_keySizeStr);
+ setDName(_dName);
+ setValidityParam(_validityStr);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-genkey handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -keyalg=" + keyPairGenerator.getAlgorithm()); //$NON-NLS-1$
+ log.fine(" -keysize=" + keySize); //$NON-NLS-1$
+ log.fine(" -sigalg=" + signatureAlgorithm.getAlgorithm()); //$NON-NLS-1$
+ log.fine(" -dname=" + distinguishedName); //$NON-NLS-1$
+ log.fine(" -validity=" + validityInDays); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws CertificateException, KeyStoreException,
+ InvalidKeyException, SignatureException, IOException,
+ NoSuchAlgorithmException
+ {
+ if (Configuration.DEBUG)
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ log.fine("About to generate key-pair..."); //$NON-NLS-1$
+ }
+ // 1. generate a new key-pair
+ keyPairGenerator.initialize(keySize);
+ KeyPair kp = keyPairGenerator.generateKeyPair();
+ PublicKey publicKey = kp.getPublic();
+ PrivateKey privateKey = kp.getPrivate();
+
+ // 2. generate a self-signed certificate
+ if (Configuration.DEBUG)
+ log.fine("About to generate a self-signed certificate..."); //$NON-NLS-1$
+ byte[] derBytes = getSelfSignedCertificate(distinguishedName,
+ publicKey,
+ privateKey);
+ if (Configuration.DEBUG)
+ log.fine(Util.dumpString(derBytes, "derBytes ")); //$NON-NLS-1$
+ CertificateFactory x509Factory = CertificateFactory.getInstance(Main.X_509);
+ ByteArrayInputStream bais = new ByteArrayInputStream(derBytes);
+ Certificate certificate = x509Factory.generateCertificate(bais);
+ if (Configuration.DEBUG)
+ log.fine("certificate = " + certificate); //$NON-NLS-1$
+
+ // 3. store it, w/ its private key, associating them to alias
+ Certificate[] chain = new Certificate[] { certificate };
+ if (Configuration.DEBUG)
+ log.fine("About to store newly generated material in key store..."); //$NON-NLS-1$
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, chain);
+
+ // 4. persist the key store
+ saveKeyStore();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.GENKEY_CMD, true);
+ result.setHeader(Messages.getString("GenKeyCmd.57")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("GenKeyCmd.58")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("GenKeyCmd.59")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("GenKeyCmd.60"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.61")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.KEYALG_OPT,
+ Messages.getString("GenKeyCmd.62"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.63")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _keyAlgorithm = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSIZE_OPT,
+ Messages.getString("GenKeyCmd.64"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.65")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _keySizeStr = argument;
+ }
+ });
+ options.add(new Option(Main.SIGALG_OPT,
+ Messages.getString("GenKeyCmd.66"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.63")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _sigAlgorithm = argument;
+ }
+ });
+ options.add(new Option(Main.DNAME_OPT,
+ Messages.getString("GenKeyCmd.68"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.69")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _dName = argument;
+ }
+ });
+ options.add(new Option(Main.KEYPASS_OPT,
+ Messages.getString("GenKeyCmd.70"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.71")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _password = argument;
+ }
+ });
+ options.add(new Option(Main.VALIDITY_OPT,
+ Messages.getString("GenKeyCmd.72"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.73")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _validityStr = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("GenKeyCmd.74"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.75")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("GenKeyCmd.76"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.77")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("GenKeyCmd.78"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.71")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("GenKeyCmd.80"), //$NON-NLS-1$
+ Messages.getString("GenKeyCmd.81")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("GenKeyCmd.82")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * @param size the desired key size as a string.
+ * @throws NumberFormatException if the string does not represent a valid
+ * decimal integer value.
+ */
+ private void setKeySize(String size)
+ {
+ if (size == null || size.trim().length() == 0)
+ this.keySize = DEFAULT_KEY_SIZE;
+ else
+ {
+ size = size.trim();
+ keySize = Integer.parseInt(size);
+ // When generating a DSA key pair, the key size must be in the range
+ // from 512 to 1024 bits, and must be a multiple of 64. The default
+ // key size for any algorithm is 1024 bits
+ if (keySize < 1)
+ throw new IllegalArgumentException(Messages.getString("GenKeyCmd.54")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @param name the X.500 distinguished name of the principal for whom the
+ * key/certificate are being generated.
+ * @throws UnsupportedCallbackException if no implementation of a name
+ * callback is available.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws IllegalArgumentException if the designated, or captured, value is
+ * not a valid X.500 distinguished name.
+ */
+ private void setDName(String name) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (name != null && name.trim().length() > 0)
+ name = name.trim();
+ else
+ {
+ // prompt user to provide one
+ String dnTxt = Messages.getString("GenKeyCmd.0"); //$NON-NLS-1$
+ String oDefault = Messages.getString("GenKeyCmd.6"); //$NON-NLS-1$
+ String lDefault = Messages.getString("GenKeyCmd.7"); //$NON-NLS-1$
+ String stDefault = Messages.getString("GenKeyCmd.8"); //$NON-NLS-1$
+ String cDefault = Messages.getString("GenKeyCmd.9"); //$NON-NLS-1$
+ String cnPrompt = Messages.getString("GenKeyCmd.10"); //$NON-NLS-1$
+ String oPrompt = Messages.getFormattedString("GenKeyCmd.11", oDefault); //$NON-NLS-1$
+ String ouPrompt = Messages.getString("GenKeyCmd.13"); //$NON-NLS-1$
+ String lPrompt = Messages.getFormattedString("GenKeyCmd.14", lDefault); //$NON-NLS-1$
+ String stPrompt = Messages.getFormattedString("GenKeyCmd.16", stDefault); //$NON-NLS-1$
+ String cPrompt = Messages.getFormattedString("GenKeyCmd.18", cDefault); //$NON-NLS-1$
+
+ TextOutputCallback dnCB = new TextOutputCallback(TextOutputCallback.INFORMATION,
+ dnTxt);
+ TextInputCallback cnCB = new TextInputCallback(cnPrompt);
+ TextInputCallback oCB = new TextInputCallback(oPrompt, oDefault);
+ TextInputCallback ouCB = new TextInputCallback(ouPrompt);
+ TextInputCallback lCB = new TextInputCallback(lPrompt, lDefault);
+ TextInputCallback sCB = new TextInputCallback(stPrompt, stDefault);
+ TextInputCallback cCB = new TextInputCallback(cPrompt, cDefault);
+ getCallbackHandler().handle(new Callback[] { dnCB, cnCB, oCB, ouCB, lCB, sCB, cCB });
+ StringBuilder sb = new StringBuilder();
+
+ // handle CN
+ name = parseUserPrompt(cnCB);
+ if (name != null && name.length() > 0)
+ sb.append("CN=").append(name); //$NON-NLS-1$
+
+ // handle O
+ name = parseUserPrompt(oCB);
+ if (name != null && name.length() > 0)
+ sb.append(",O=").append(name); //$NON-NLS-1$
+
+ // handle OU
+ name = parseUserPrompt(ouCB);
+ if (name != null && name.length() > 0)
+ sb.append(",OU=").append(name.trim()); //$NON-NLS-1$
+
+ // handle L
+ name = parseUserPrompt(lCB);
+ if (name != null && name.length() > 0)
+ sb.append(",L=").append(name.trim()); //$NON-NLS-1$
+
+ // handle ST
+ name = parseUserPrompt(sCB);
+ if (name != null && name.length() > 0)
+ sb.append(",ST=").append(name.trim()); //$NON-NLS-1$
+
+ // handle C
+ name = parseUserPrompt(cCB);
+ if (name != null && name.length() > 0)
+ sb.append(",C=").append(name.trim()); //$NON-NLS-1$
+
+ name = sb.toString().trim();
+ }
+ if (Configuration.DEBUG)
+ log.fine("dName=[" + name + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ distinguishedName = new X500DistinguishedName(name);
+ }
+
+ private String parseUserPrompt(TextInputCallback ticb)
+ {
+ String result = ticb.getText();
+ if (result == null || result.trim().length() == 0)
+ result = ticb.getDefaultText();
+ else if (result.trim().equals(".")) //$NON-NLS-1$
+ result = null;
+ else
+ result = result.trim();
+
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java
new file mode 100644
index 000000000..e52c90299
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java
@@ -0,0 +1,232 @@
+/* IdentityDBCmd.java -- The identitydb command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.util.logging.Logger;
+
+/**
+ * <b>NOT IMPLEMENTED YET</b>
+ * <p>
+ * The <b>-identitydb</b> keytool command handler is used to read the JDK 1.1.x-
+ * style identity database and add its entries to the key store. If a key store
+ * does not exist, it is created.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the identity file to import. If this
+ * option is omitted, the tool will process STDIN.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class IdentityDBCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(IdentityDBCmd.class.getName());
+ protected String _idbFileName;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._idbFileName = pathName;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_idbFileName);
+ setKeyStoreParams(true, _providerClassName, _ksType, _ksPassword, _ksURL);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-identitydb handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -file=" + _idbFileName); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.IDENTITYDB_CMD, true);
+ result.setHeader(Messages.getString("IdentityDBCmd.7")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("IdentityDBCmd.8")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("IdentityDBCmd.9")); //$NON-NLS-1$
+ options.add(new Option(Main.FILE_OPT,
+ Messages.getString("IdentityDBCmd.10"), //$NON-NLS-1$
+ Messages.getString("IdentityDBCmd.11")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _idbFileName = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("IdentityDBCmd.12"), //$NON-NLS-1$
+ Messages.getString("IdentityDBCmd.13")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("IdentityDBCmd.14"), //$NON-NLS-1$
+ Messages.getString("IdentityDBCmd.15")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("IdentityDBCmd.16"), //$NON-NLS-1$
+ Messages.getString("IdentityDBCmd.17")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("IdentityDBCmd.18"), //$NON-NLS-1$
+ Messages.getString("IdentityDBCmd.19")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("IdentityDBCmd.20")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/ImportCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/ImportCmd.java
new file mode 100644
index 000000000..b68760d09
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/ImportCmd.java
@@ -0,0 +1,930 @@
+/* ImportCmd.java -- The import command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.SystemProperties;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.security.x509.X509CertPath;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <code>-import</code> keytool command handler is used to read an X.509
+ * certificate, or a PKCS#7 Certificate Reply from a designated input source and
+ * incorporate the certificates into the key store.
+ * <p>
+ * If the <i>Alias</i> does not already exist in the key store, the tool treats
+ * the certificate read from the input source as a new Trusted Certificate. It
+ * then attempts to discover a chain-of-trust, starting from that certificate
+ * and ending at another <i>Trusted Certificate</i>, already stored in the key
+ * store. If the <code>-trustcacerts</code> option is present, an additional
+ * key store, of type <code>JKS</code> named <code>cacerts</code>, and assumed
+ * to be present in <code>${JAVA_HOME}/lib/security</code> will also be
+ * consulted if found --<code>${JAVA_HOME}</code> refers to the location of an
+ * installed Java Runtime Environment (JRE). If no chain-of-trust can be
+ * established, and unless the <code>-noprompt</code> option has been specified,
+ * the certificate is printed to STDOUT and the user is prompted for a
+ * confirmation.
+ * <p>
+ * If <i>Alias</i> exists in the key store, the tool will treat the
+ * certificate(s) read from the input source as a <i>Certificate Reply</i>,
+ * which can be a chain of certificates, that eventually would replace the chain
+ * of certificates associated with the <i>Key Entry</i> of that <i>Alias</i>.
+ * The substitution of the certificates only occurs if a chain-of-trust can be
+ * established between the bottom certificate of the chain read from the input
+ * file and the <i>Trusted Certificates</i> already present in the key store.
+ * Again, if the <code>-trustcacerts</code> option is specified, additional
+ * <i>Trusted Certificates</i> in the same <code>cacerts</code> key store will
+ * be considered. If no chain-of-trust can be established, the operation will
+ * abort.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the file to read from. If omitted, the
+ * tool will process STDIN.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * protect the <i>Key Entry</i> associated with the designated <i>Alias</i>,
+ * when replacing this <i>Alias</i>' chain of certificates with that found
+ * in the certificate reply.
+ * <p>
+ * If this option is omitted, and the chain-of-trust for the certificate
+ * reply has been established, the tool will first attempt to unlock the
+ * <i>Key Entry</i> using the same password protecting the key store. If
+ * this fails, you will then be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-noprompt</dt>
+ * <dd>Use this option to prevent the tool from prompting the user.
+ * <p></dd>
+ *
+ * <dt>-trustcacerts</dt>
+ * <dd>Use this option to indicate to the tool that a key store, of type
+ * <code>JKS</code>, named <code>cacerts</code>, and usually located in
+ * <code>lib/security</code> in an installed Java Runtime Environment
+ * should be considered when trying to establish chain-of-trusts.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class ImportCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(ImportCmd.class.getName());
+ private static final String GKR = "gkr"; //$NON-NLS-1$
+ private static final String JKS = "jks"; //$NON-NLS-1$
+ private static final String LIB = "lib"; //$NON-NLS-1$
+ private static final String SECURITY = "security"; //$NON-NLS-1$
+ private static final String CACERTS = "cacerts"; //$NON-NLS-1$
+ private static final String CACERTS_GKR = CACERTS + "." + GKR; //$NON-NLS-1$
+ protected String _alias;
+ protected String _certFileName;
+ protected String _password;
+ protected boolean noPrompt;
+ protected boolean trustCACerts;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ private CertificateFactory x509Factory;
+ /**
+ * Pathname to a GKR-type cacerts file to use when trustCACerts is true. This
+ * is usually a file named "cacerts.gkr" located in lib/security in the folder
+ * specified by the system-property "gnu.classpath.home".
+ */
+ private String gkrCaCertsPathName;
+ /**
+ * Pathname to a JKS-type cacerts file to use when trustCACerts is true. This
+ * is usually a file named "cacerts" located in lib/security in the folder
+ * specified by the system-property "java.home".
+ */
+ private String jksCaCertsPathName;
+ /** Alias self-signed certificate. used when importing certificate replies. */
+ private X509Certificate selfSignedCertificate;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the existing alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certFileName = pathName;
+ }
+
+ /** @param password the existing (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /**
+ * @param flag whether to prompt, or not, the user to verify certificate
+ * fingerprints.
+ */
+ public void setNoprompt(String flag)
+ {
+ this.noPrompt = Boolean.valueOf(flag).booleanValue();
+ }
+
+ /**
+ * @param flag whether to trust, or not, certificates found in the
+ * <code>cacerts</code> key store.
+ */
+ public void setTrustcacerts(String flag)
+ {
+ this.trustCACerts = Boolean.valueOf(flag).booleanValue();
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_certFileName);
+ setKeyStoreParams(true, _providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-import handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -file=" + _certFileName); //$NON-NLS-1$
+ log.fine(" -noprompt=" + noPrompt); //$NON-NLS-1$
+ log.fine(" -trustcacerts=" + trustCACerts); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws CertificateException, KeyStoreException, IOException,
+ UnsupportedCallbackException, NoSuchAlgorithmException,
+ CertPathValidatorException, UnrecoverableKeyException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ if (trustCACerts)
+ {
+ String fs = SystemProperties.getProperty("file.separator"); //$NON-NLS-1$
+ String classpathHome = SystemProperties.getProperty("gnu.classpath.home"); //$NON-NLS-1$
+ gkrCaCertsPathName = new StringBuilder(classpathHome).append(fs)
+ .append(LIB).append(fs)
+ .append(SECURITY).append(fs)
+ .append(CACERTS_GKR).toString();
+ String javaHome = SystemProperties.getProperty("java.home"); //$NON-NLS-1$
+ jksCaCertsPathName = new StringBuilder(javaHome).append(fs)
+ .append(LIB).append(fs)
+ .append(SECURITY).append(fs)
+ .append(CACERTS).toString();
+ }
+ x509Factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+ // the alias will tell us whether we're dealing with
+ // a new trusted certificate or a certificate reply
+ if (! store.containsAlias(alias))
+ importNewTrustedCertificate();
+ else
+ {
+ ensureAliasIsKeyEntry();
+ importCertificateReply();
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.IMPORT_CMD, true);
+ result.setHeader(Messages.getString("ImportCmd.27")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("ImportCmd.26")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("ImportCmd.25")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("ImportCmd.24"), //$NON-NLS-1$
+ Messages.getString("ImportCmd.23")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.FILE_OPT,
+ Messages.getString("ImportCmd.22"), //$NON-NLS-1$
+ Messages.getString("ImportCmd.21")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _certFileName = argument;
+ }
+ });
+ options.add(new Option(Main.KEYPASS_OPT,
+ Messages.getString("ImportCmd.20"), //$NON-NLS-1$
+ Messages.getString("ImportCmd.19")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _password = argument;
+ }
+ });
+ options.add(new Option("noprompt", //$NON-NLS-1$
+ Messages.getString("ImportCmd.18")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ noPrompt = true;
+ }
+ });
+ options.add(new Option("trustcacerts", //$NON-NLS-1$
+ Messages.getString("ImportCmd.17")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ trustCACerts = true;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("ImportCmd.16"), //$NON-NLS-1$
+ Messages.getString("ImportCmd.15")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("ImportCmd.14"), //$NON-NLS-1$
+ Messages.getString("ImportCmd.13")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("ImportCmd.12"), //$NON-NLS-1$
+ Messages.getString("ImportCmd.11")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("ImportCmd.10"), //$NON-NLS-1$
+ Messages.getString("ImportCmd.9")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("ImportCmd.8")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * When importing a new trusted certificate, <i>alias</i> MUST NOT yet exist
+ * in the key store.
+ * <p>
+ * Before adding the certificate to the key store and associate it with the
+ * designated Alias, this method tries to verify it by attempting to construct
+ * a chain of trust from that certificate to a self-signed certificate
+ * (belonging to a root CA), using (already) trusted certificates that are
+ * available in the key store.
+ * <p>
+ * If the <code>-trustcacerts</code> option was detected on the command
+ * line, additional trusted certificates are considered for establishing the
+ * chain of trust. Those additional certificates are assumed to be in a key
+ * store, of type <code>JKS</code> named <code>cacerts</code> and usually
+ * located in <code>${JAVA_HOME}/lib/security</code>, where
+ * <code>${JAVA_HOME}</code> is the root folder location of a Java runtime.
+ * <p>
+ * If this method fails to establish a trust path from the certificate to be
+ * imported up to a trusted self-signed certificate, the certificate is
+ * printed to <code>STDOUT</code>, and the user is prompted to verify it,
+ * with the option of aborting the import operation. If however the option
+ * <code>-noprompt</code> was detected on the command line, no interaction
+ * with the user will take place and the import operation will abort.
+ *
+ * @throws CertificateException
+ * @throws KeyStoreException
+ * @throws NoSuchAlgorithmException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws CertPathValidatorException
+ */
+ private void importNewTrustedCertificate() throws CertificateException,
+ KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, CertPathValidatorException,
+ UnrecoverableKeyException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "importNewTrustedCertificate"); //$NON-NLS-1$
+ Certificate certificate = x509Factory.generateCertificate(inStream);
+ if (Configuration.DEBUG)
+ log.fine("certificate = " + certificate); //$NON-NLS-1$
+ LinkedList orderedReply = new LinkedList();
+ orderedReply.addLast(certificate);
+
+ if (findTrustAndUpdate(orderedReply, ! noPrompt))
+ {
+ store.setCertificateEntry(alias, certificate);
+ System.out.println(Messages.getString("ImportCmd.29")); //$NON-NLS-1$
+ saveKeyStore();
+ }
+ else
+ System.out.println(Messages.getString("ImportCmd.28")); //$NON-NLS-1$
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "importNewTrustedCertificate"); //$NON-NLS-1$
+ }
+
+ /**
+ * A certificate reply is a certificate, whose Owner is stored in the key
+ * store associated to the designated Alias, and now signed by supposedly a
+ * trusted CA (Certificate Authority). In other words, the Subject in this
+ * certificate reply is Alias's own and the Issuer is a CA.
+ * <p>
+ * When importing a certificate reply, the reply is validated using trusted
+ * certificates from the key store, and optionally (if the option
+ * <code>-trustcacerts</code> was detected on the command line) certificates
+ * found in the key store, of type <code>JKS</code> named <code>cacerts</code>
+ * located in <code>${JAVA_HOME}/lib/security</code>, where
+ * <code>${JAVA_HOME}</code> is the root folder location of a Java runtime.
+ *
+ * @throws CertificateException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws KeyStoreException
+ * @throws CertPathValidatorException
+ * @throws NoSuchAlgorithmException
+ * @throws UnrecoverableKeyException
+ */
+ private void importCertificateReply() throws CertificateException,
+ IOException, UnsupportedCallbackException, KeyStoreException,
+ NoSuchAlgorithmException, CertPathValidatorException,
+ UnrecoverableKeyException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "importCertificateReply"); //$NON-NLS-1$
+ Collection certificates = x509Factory.generateCertificates(inStream);
+ ensureReplyIsOurs(certificates);
+ // we now have established that the public keys are the same.
+ // find a chain-of-trust if one exists
+ if (certificates.size() == 1)
+ importCertificate((Certificate) certificates.iterator().next());
+ else
+ importChain(certificates);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "importCertificateReply"); //$NON-NLS-1$
+ }
+
+ /**
+ * If the reply is a single X.509 certificate, keytool attempts to establish a
+ * trust chain, starting at the certificate reply and ending at a self-signed
+ * certificate (belonging to a root CA). The certificate reply and the
+ * hierarchy of certificates used to authenticate the certificate reply form
+ * the new certificate chain of alias. If a trust chain cannot be established,
+ * the certificate reply is not imported. In this case, keytool does not print
+ * out the certificate, nor does it prompt the user to verify it. This is
+ * because it is very hard (if not impossible) for a user to determine the
+ * authenticity of the certificate reply.
+ *
+ * @param certificate the certificate reply to import into the key store.
+ * @throws NoSuchAlgorithmException
+ * @throws CertPathValidatorException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws KeyStoreException
+ * @throws CertificateException
+ */
+ private void importCertificate(Certificate certificate)
+ throws NoSuchAlgorithmException, CertPathValidatorException,
+ KeyStoreException, UnrecoverableKeyException, IOException,
+ UnsupportedCallbackException, CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "importCertificate", certificate); //$NON-NLS-1$
+ LinkedList reply = new LinkedList();
+ reply.addLast(certificate);
+
+ if (! findTrustAndUpdate(reply, false))
+ throw new CertPathValidatorException(Messages.getString("ImportCmd.34")); //$NON-NLS-1$
+
+ Certificate[] newChain = (Certificate[]) reply.toArray(new Certificate[0]);
+ Key privateKey = getAliasPrivateKey();
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, newChain);
+ saveKeyStore();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "importCertificate"); //$NON-NLS-1$
+ }
+
+ /**
+ * If the reply is a PKCS#7 formatted certificate chain, the chain is first
+ * ordered (with the user certificate first and the self-signed root CA
+ * certificate last), before keytool attempts to match the root CA certificate
+ * provided in the reply with any of the trusted certificates in the key store
+ * or the "cacerts" keystore file (if the -trustcacerts option was specified).
+ * If no match can be found, the information of the root CA certificate is
+ * printed out, and the user is prompted to verify it, e.g., by comparing the
+ * displayed certificate fingerprints with the fingerprints obtained from some
+ * other (trusted) source of information, which might be the root CA itself.
+ * The user then has the option of aborting the import operation. If the
+ * -noprompt option is given, however, there will be no interaction with the
+ * user.
+ *
+ * @param chain the collection of certificates parsed from the user
+ * designated input.
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws KeyStoreException
+ * @throws CertPathValidatorException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ */
+ private void importChain(Collection chain) throws NoSuchAlgorithmException,
+ CertPathValidatorException, KeyStoreException, UnrecoverableKeyException,
+ IOException, UnsupportedCallbackException, CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "importChain", chain); //$NON-NLS-1$
+ LinkedList reply = orderChain(chain);
+ if (findTrustAndUpdate(reply, ! noPrompt))
+ {
+ Certificate[] newChain = (Certificate[]) reply.toArray(new Certificate[0]);
+ Key privateKey = getAliasPrivateKey();
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, newChain);
+ saveKeyStore();
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "importChain"); //$NON-NLS-1$
+ }
+
+ /**
+ * Check to ensure that alias's public key is the subject of the first
+ * certificate in the passed certificate collection. Throws an exception if
+ * the public keys do not match.
+ *
+ * @param certificates a {@link Collection} of certificate replies (either a
+ * signle certificate reply, or a PKCS#7 certificate reply chain)
+ * usually sent by a CA as a response to a Certificate Signing
+ * Request (CSR).
+ * @throws IOException
+ * @throws UnsupportedCallbackException
+ * @throws KeyStoreException
+ */
+ private void ensureReplyIsOurs(Collection certificates) throws IOException,
+ UnsupportedCallbackException, KeyStoreException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "ensureReplyIsOurs"); //$NON-NLS-1$
+ Certificate certificate = (Certificate) certificates.iterator().next();
+ if (Configuration.DEBUG)
+ log.fine("certificate = " + certificate); //$NON-NLS-1$
+ Certificate[] chain = store.getCertificateChain(alias);
+ if (chain == null)
+ throw new IllegalArgumentException(Messages.getFormattedString("ImportCmd.37", //$NON-NLS-1$
+ alias));
+ selfSignedCertificate = (X509Certificate) chain[0];
+ PublicKey anchorPublicKey = selfSignedCertificate.getPublicKey();
+ PublicKey certPublicKey = certificate.getPublicKey();
+ boolean sameKey;
+ if (anchorPublicKey instanceof DSAPublicKey)
+ {
+ DSAPublicKey pk1 = (DSAPublicKey) anchorPublicKey;
+ if (!(certPublicKey instanceof DSAPublicKey))
+ throw new IllegalArgumentException(Messages.getString("ImportCmd.38")); //$NON-NLS-1$
+
+ sameKey = areEqual(pk1, (DSAPublicKey) certPublicKey);
+ }
+ else if (anchorPublicKey instanceof RSAPublicKey)
+ {
+ RSAPublicKey pk1 = (RSAPublicKey) anchorPublicKey;
+ if (!(certPublicKey instanceof RSAPublicKey))
+ throw new IllegalArgumentException(Messages.getString("ImportCmd.38")); //$NON-NLS-1$
+
+ sameKey = areEqual(pk1, (RSAPublicKey) certPublicKey);
+ }
+ else
+ throw new IllegalArgumentException(
+ Messages.getFormattedString("ImportCmd.40", //$NON-NLS-1$
+ new String[] { alias,
+ anchorPublicKey.getClass().getName() }));
+ if (! sameKey)
+ throw new IllegalArgumentException(Messages.getString("ImportCmd.41")); //$NON-NLS-1$
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "ensureReplyIsOurs"); //$NON-NLS-1$
+ }
+
+ private boolean areEqual(DSAPublicKey pk1, DSAPublicKey pk2)
+ {
+ if (pk1.getY().compareTo(pk2.getY()) != 0)
+ return false;
+
+ DSAParams p1 = pk1.getParams();
+ DSAParams p2 = pk2.getParams();
+ if (p1.getG().compareTo(p2.getG()) != 0)
+ return false;
+
+ if (p1.getP().compareTo(p2.getP()) != 0)
+ return false;
+
+ return p1.getQ().compareTo(p2.getQ()) == 0;
+ }
+
+ private boolean areEqual(RSAPublicKey pk1, RSAPublicKey pk2)
+ {
+ if (pk1.getPublicExponent().compareTo(pk2.getPublicExponent()) != 0)
+ return false;
+
+ return pk1.getModulus().compareTo(pk2.getModulus()) == 0;
+ }
+
+ /**
+ * Given a collection of certificates returned as a certificate-reply, this
+ * method sorts the certificates in the collection so that the <i>Issuer</i>
+ * of the certificate at position <code>i</code> is the <i>Subject</i> of
+ * the certificate at position <code>i + 1</code>.
+ * <p>
+ * This method uses <code>selfSignedCertificate</code> to discover the first
+ * certificate in the chain. The <i>Trust Anchor</i> of the chain; i.e. the
+ * self-signed CA certificate, if it exsits, will be discovered/established
+ * later by an appropriate <i>Certificate Path Validator</i>.
+ * <p>
+ * An exception is thrown if (a) no initial certificate is found in the
+ * designated collection which can be used as the start of the chain, or (b)
+ * if a chain can not be constructed using all the certificates in the
+ * designated collection.
+ *
+ * @param chain a collection of certificates, not necessarily ordered, but
+ * assumed to include a CA certificate authenticating our alias
+ * public key, which is the subject of the alias self-signed
+ * certificate.
+ * @return the input collection, ordered with own certificate first, and CA's
+ * self-signed certificate last.
+ */
+ private LinkedList orderChain(Collection chain)
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "orderChain"); //$NON-NLS-1$
+ LinkedList in = new LinkedList(chain);
+ int initialCount = in.size();
+ LinkedList result = new LinkedList();
+ Principal issuer = selfSignedCertificate.getIssuerDN();
+ ListIterator it;
+ outer: while (in.size() > 0)
+ {
+ for (it = in.listIterator(); it.hasNext();)
+ {
+ X509Certificate certificate = (X509Certificate) it.next();
+ if (issuer.equals(certificate.getSubjectDN()))
+ {
+ it.remove();
+ result.addLast(certificate);
+ issuer = certificate.getIssuerDN();
+ continue outer;
+ }
+ }
+ throw new IllegalArgumentException(
+ Messages.getFormattedString(Messages.getString("ImportCmd.7"), //$NON-NLS-1$
+ new Object[] { Integer.valueOf(result.size()),
+ Integer.valueOf(initialCount) }));
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "orderChain", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Given an ordered list of certificates, this method attempts to validate the
+ * chain, and if successful, updates the key store entry for the designated
+ * alias. The list of certificates is expected to be ordered as a chain, where
+ * the first is the alias's own certificate and the last being a self-signed
+ * CA certificate.
+ * <p>
+ * if <code>promptUser</code> is <code>true</code>, then even if no
+ * anchor trust certificate is found, the user is prompted to approve, or not,
+ * the import operation. On the other hand if the <code>promptUser</code>
+ * parameter is <code>false</code> then this method will throw an exception
+ * if no trust anchor is to be found.
+ *
+ * @param reply an ordered certificate path, where the last entry is the CA's
+ * self-signed certificate.
+ * @param promptUser a boolean flag indicating whether or not to prompt the
+ * user for explicit trust in a CA certificate.
+ * @return <code>true</code> if the validation succeeds; or <code>false</code>
+ * otherwise.
+ * @throws NoSuchAlgorithmException
+ * @throws CertPathValidatorException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws KeyStoreException
+ * @throws CertificateEncodingException
+ */
+ private boolean findTrustAndUpdate(LinkedList reply, boolean promptUser)
+ throws IOException, NoSuchAlgorithmException, CertPathValidatorException,
+ KeyStoreException, UnrecoverableKeyException, UnsupportedCallbackException,
+ CertificateEncodingException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "findTrustAndUpdate"); //$NON-NLS-1$
+ CertPathValidator validator = CertPathValidator.getInstance("PKIX"); //$NON-NLS-1$
+ X509CertPath certPath = new X509CertPath(reply);
+ PKIXCertPathValidatorResult cpvr = findTrustInStore(certPath, validator);
+ if (cpvr == null && trustCACerts) // try cacerts.gkr - a GKR key store
+ {
+ PKIXParameters params = getCertPathParameters(GKR, gkrCaCertsPathName);
+ cpvr = validate(validator, certPath, params);
+ if (cpvr == null) // try cacerts - a JKS key store
+ {
+ params = getCertPathParameters(JKS, jksCaCertsPathName);
+ cpvr = validate(validator, certPath, params);
+ }
+ }
+ boolean result = false;
+ if (cpvr == null)
+ {
+ if (promptUser)
+ {
+ printVerbose((Certificate) reply.getLast());
+ ConfirmationCallback ccb;
+ ccb = new ConfirmationCallback(Messages.getString("ImportCmd.32"), //$NON-NLS-1$
+ ConfirmationCallback.INFORMATION,
+ ConfirmationCallback.YES_NO_OPTION,
+ ConfirmationCallback.NO);
+ getCallbackHandler().handle(new Callback[] { ccb });
+ int answer = ccb.getSelectedIndex();
+ result = answer == ConfirmationCallback.YES;
+ }
+ }
+ else
+ {
+ TrustAnchor anchor = cpvr.getTrustAnchor();
+ log.fine("Found a chain-of-trust anchored by " + anchor); //$NON-NLS-1$
+ Certificate trustedCert = anchor.getTrustedCert();
+ reply.addLast(trustedCert);
+ result = true;
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "findTrustAndUpdate", //$NON-NLS-1$
+ Boolean.valueOf(result));
+ return result;
+ }
+
+ private PKIXCertPathValidatorResult findTrustInStore(X509CertPath certPath,
+ CertPathValidator validator)
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "findTrustInStore"); //$NON-NLS-1$
+ PKIXCertPathValidatorResult result;
+ try
+ {
+ PKIXParameters params = new PKIXParameters(store);
+ result = (PKIXCertPathValidatorResult) validator.validate(certPath, params);
+ }
+ catch (Exception x)
+ {
+ log.log(Level.FINE,
+ "Exception in findTrustInStore(). Ignore + Return NULL", //$NON-NLS-1$
+ x);
+ result = null;
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "findTrustInStore", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Return an instance of {@link PKIXParameters} constructed using a key store
+ * of the designated type and located at the designated path.
+ *
+ * @param type the type of the key-store to load.
+ * @param pathName the local File System fully qualified path name to the key
+ * store.
+ * @return an instance of <code>CertPathParameters</code> to use for
+ * validating certificates and certificate replies.
+ */
+ private PKIXParameters getCertPathParameters(String type, String pathName)
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getCertPathParameters", //$NON-NLS-1$
+ new Object[] { type, pathName });
+ FileInputStream stream = null;
+ PKIXParameters result = null;
+ try
+ {
+ KeyStore cacerts = KeyStore.getInstance(type);
+ stream = new FileInputStream(pathName);
+ cacerts.load(stream, "changeit".toCharArray()); //$NON-NLS-1$
+ result = new PKIXParameters(cacerts);
+ }
+ catch (Exception x)
+ {
+ if (Configuration.DEBUG)
+ log.log(Level.FINE, "Exception in getCertPathParameters(). Ignore", x); //$NON-NLS-1$
+ }
+ finally
+ {
+ if (stream != null)
+ try
+ {
+ stream.close();
+ }
+ catch (Exception ignored)
+ {
+ }
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getCertPathParameters", result); //$NON-NLS-1$
+ return result;
+ }
+
+ private PKIXCertPathValidatorResult validate(CertPathValidator validator,
+ X509CertPath certPath,
+ PKIXParameters params)
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "validate"); //$NON-NLS-1$
+ PKIXCertPathValidatorResult result = null;
+ if (params != null)
+ try
+ {
+ result = (PKIXCertPathValidatorResult) validator.validate(certPath,
+ params);
+ }
+ catch (Exception x)
+ {
+ if (Configuration.DEBUG)
+ log.log(Level.FINE, "Exception in validate(). Ignore", x); //$NON-NLS-1$
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "validate", result); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java
new file mode 100644
index 000000000..a05a5962f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java
@@ -0,0 +1,407 @@
+/* KeyCloneCmd.java -- The keyclone command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-keyclone</b> keytool command handler is used to clone an existing
+ * key store entry associated with a designated alias, with its private key and
+ * chain of certificates.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-dest ALIAS</dt>
+ * <dd>Use this option to specify the new <i>Alias</i> which will be used
+ * to identify the cloned copy of the <i>Key Entry</i>.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * unlock the <i>Key Entry</i> associated with the designated <i>Alias</i>.
+ * <p>
+ * If this option is omitted, the tool will first attempt to unlock the
+ * <i>Key Entry</i> using the same password protecting the key store. If
+ * this fails, you will then be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-new PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the private key
+ * material of the newly cloned copy of the <i>Key Entry</i>.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class KeyCloneCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(KeyCloneCmd.class.getName());
+ protected String _alias;
+ protected String _destAlias;
+ protected String _password;
+ protected String _newPassword;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ private String destinationAlias;
+ private char[] newKeyPasswordChars;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the existing alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param alias the new alias to use. */
+ public void setDest(String alias)
+ {
+ this._destAlias = alias;
+ }
+
+ /** @param password the existing (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param password the new (private) key password to use. */
+ public void setNew(String password)
+ {
+ this._newPassword = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+ setDestinationAlias(_destAlias);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-keyclone handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -dest=" + destinationAlias); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ if (store.containsAlias(destinationAlias))
+ throw new SecurityException(Messages.getString("KeyCloneCmd.23")); //$NON-NLS-1$
+
+ Key privateKey = getAliasPrivateKey();
+
+ setNewKeyPassword(_newPassword);
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ store.setKeyEntry(destinationAlias, privateKey, newKeyPasswordChars, chain);
+
+ saveKeyStore();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.KEYCLONE_CMD, true);
+ result.setHeader(Messages.getString("KeyCloneCmd.22")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("KeyCloneCmd.21")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("KeyCloneCmd.20")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("KeyCloneCmd.19"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.16")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.DEST_OPT,
+ Messages.getString("KeyCloneCmd.17"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.16")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _destAlias = argument;
+ }
+ });
+ options.add(new Option(Main.KEYPASS_OPT,
+ Messages.getString("KeyCloneCmd.15"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _password = argument;
+ }
+ });
+ options.add(new Option(Main.NEW_OPT,
+ Messages.getString("KeyCloneCmd.13"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _newPassword = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("KeyCloneCmd.11"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.10")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("KeyCloneCmd.9"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.8")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("KeyCloneCmd.7"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("KeyCloneCmd.5"), //$NON-NLS-1$
+ Messages.getString("KeyCloneCmd.4")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("KeyCloneCmd.3")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ private void setDestinationAlias(String name) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (name == null || name.trim().length() == 0) // ask user to provide one
+ {
+ NameCallback ncb = new NameCallback(Messages.getString("KeyCloneCmd.26")); //$NON-NLS-1$
+ getCallbackHandler().handle(new Callback[] { ncb });
+ name = ncb.getName();
+ if (name == null || name.trim().length() == 0)
+ throw new IllegalArgumentException(Messages.getString("KeyCloneCmd.27")); //$NON-NLS-1$
+ }
+
+ destinationAlias = name.trim();
+ }
+
+ private void setNewKeyPassword(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null)
+ newKeyPasswordChars = password.toCharArray();
+ else // ask user to provide one
+ {
+ boolean ok = false;
+ Callback[] prompts = new Callback[1];
+ Callback[] errors = new Callback[1];
+ for (int i = 0; i < 3; i++)
+ if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
+ {
+ ok = true;
+ break;
+ }
+ if (! ok)
+ throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
+ }
+ }
+
+ private boolean prompt4NewPassword(CallbackHandler handler,
+ Callback[] prompts, Callback[] errors)
+ throws IOException, UnsupportedCallbackException
+ {
+ String p = Messages.getFormattedString("KeyCloneCmd.28", //$NON-NLS-1$
+ new String[] { destinationAlias,
+ String.valueOf(keyPasswordChars) });
+ PasswordCallback pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd1 = pcb.getPassword();
+ pcb.clearPassword();
+ if (pwd1 == null || pwd1.length == 0)
+ {
+ newKeyPasswordChars = (char[]) keyPasswordChars.clone();
+ return true;
+ }
+
+ if (pwd1.length < 6)
+ {
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR,
+ Messages.getString("StorePasswdCmd.21")); //$NON-NLS-1$
+ handler.handle(errors);
+ return false;
+ }
+
+ newKeyPasswordChars = pwd1;
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java
new file mode 100644
index 000000000..7652cc843
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java
@@ -0,0 +1,395 @@
+/* KeyPasswdCmd.java -- The keypasswd command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.SystemProperties;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-keypasswd</b> keytool command handler is used to change the password
+ * protecting the private key associated to a designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * unlock the <i>Key Entry</i> associated with the designated <i>Alias</i>.
+ * <p>
+ * If this option is omitted, the tool will first attempt to unlock the
+ * <i>Key Entry</i> using the same password protecting the key store. If
+ * this fails, you will then be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-new PASSWORD</dt>
+ * <dd>The new, and different, password which will be used to protect the
+ * private key material of the designated Key Entry.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class KeyPasswdCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(KeyPasswdCmd.class.getName());
+ protected String _alias;
+ protected String _password;
+ protected String _newPassword;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ private char[] newPasswordChars;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param password the existing (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param password the new (private) key password to use. */
+ public void setNew(String password)
+ {
+ this._newPassword = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-keypasswd handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -new=" + _newPassword); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ // 1. get the key entry and certificate chain associated to alias
+ Key privateKey = getAliasPrivateKey();
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ // 2. replace the old entry
+ setNewKeyPassword(_newPassword);
+ store.setKeyEntry(alias, privateKey, newPasswordChars, chain);
+
+ // 3. persist the key store
+ saveKeyStore();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.KEYPASSWD_CMD, true);
+ result.setHeader(Messages.getString("KeyPasswdCmd.23")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("KeyPasswdCmd.22")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("KeyPasswdCmd.21")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("KeyPasswdCmd.20"), //$NON-NLS-1$
+ Messages.getString("KeyPasswdCmd.19")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.KEYPASS_OPT,
+ Messages.getString("KeyPasswdCmd.18"), //$NON-NLS-1$
+ Messages.getString("KeyPasswdCmd.9")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _password = argument;
+ }
+ });
+ options.add(new Option(Main.NEW_OPT,
+ Messages.getString("KeyPasswdCmd.16"), //$NON-NLS-1$
+ Messages.getString("KeyPasswdCmd.9")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _newPassword = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("KeyPasswdCmd.14"), //$NON-NLS-1$
+ Messages.getString("KeyPasswdCmd.13")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("KeyPasswdCmd.12"), //$NON-NLS-1$
+ Messages.getString("KeyPasswdCmd.11")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("KeyPasswdCmd.10"), //$NON-NLS-1$
+ Messages.getString("KeyPasswdCmd.9")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("KeyPasswdCmd.8"), //$NON-NLS-1$
+ Messages.getString("KeyPasswdCmd.7")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("KeyPasswdCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Set the new password to use for protecting Alias's private key.
+ *
+ * @param password the new key password. if <code>null</code> prompt the
+ * user to provide one. When prompting, the password is entered twice
+ * and compared for a match.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws UnsupportedCallbackException if no implementation of a password
+ * callback handler was found.
+ */
+ private void setNewKeyPassword(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null)
+ newPasswordChars = password.toCharArray();
+ else
+ {
+ boolean ok = false;
+ Callback[] prompts = new Callback[1];
+ Callback[] errors = new Callback[1];
+ for (int i = 0; i < 3; i++)
+ if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
+ {
+ ok = true;
+ break;
+ }
+ if (! ok)
+ throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
+ }
+ }
+
+ private boolean prompt4NewPassword(CallbackHandler handler,
+ Callback[] prompts, Callback[] errors)
+ throws IOException, UnsupportedCallbackException
+ {
+ // prompt user (1st time) to provide one
+ String p = Messages.getFormattedString("KeyPasswdCmd.24", alias); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd1 = pcb.getPassword();
+ pcb.clearPassword();
+ String ls = SystemProperties.getProperty("line.separator"); //$NON-NLS-1$
+ if (pwd1 == null || pwd1.length < 6)
+ {
+ String m = Messages.getString("StorePasswdCmd.21") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ if (Arrays.equals(keyPasswordChars, pwd1))
+ {
+ String m = Messages.getString("StorePasswdCmd.22") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ // prompt user (2nd time) for confirmation
+ p = Messages.getFormattedString("KeyPasswdCmd.28", alias); //$NON-NLS-1$
+ pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd2 = pcb.getPassword();
+ pcb.clearPassword();
+ if (! Arrays.equals(pwd1, pwd2))
+ {
+ String m = Messages.getString("StorePasswdCmd.24") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ newPasswordChars = pwd2;
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/ListCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/ListCmd.java
new file mode 100644
index 000000000..55c8c7683
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/ListCmd.java
@@ -0,0 +1,432 @@
+/* ListCmd.java -- The list command handler of the keytool
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.util.Base64;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.Enumeration;
+import java.util.logging.Logger;
+
+/**
+ * The <b>-list</b> keytool command handler is used to output one or all key
+ * store entries.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-rfc</dt>
+ * <dd>Use RFC-1421 specifications when encoding the output.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Output the certificate in human-readable format. If both this option
+ * and the <code>-rfc</code> option are detected on the command line, the
+ * tool will opt for the human-readable form and will not abort the
+ * command.</dd>
+ * </dl>
+ */
+class ListCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(ListCmd.class.getName());
+ protected String _alias;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ protected boolean rfc;
+ private boolean all;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ /**
+ * @param flag whether to use, or not, RFC-1421 format when listing the
+ * certificate(s).
+ */
+ public void setRfc(String flag)
+ {
+ this.rfc = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(null); // use stdout
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ all = _alias == null;
+ if (! all)
+ setAliasParam(_alias);
+
+ if (verbose & rfc)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Both -v and -rfc options were found on the command line. " //$NON-NLS-1$
+ + "Only the former will be considered"); //$NON-NLS-1$
+ rfc = false;
+ }
+ if (Configuration.DEBUG)
+ {
+ log.fine("-list handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ log.fine(" -rfc=" + rfc); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, CertificateEncodingException,
+ IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ PrintWriter writer = new PrintWriter(outStream, true);
+ writer.println(Messages.getFormattedString("ListCmd.21", store.getType())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("ListCmd.22", //$NON-NLS-1$
+ store.getProvider().getName()));
+ if (all)
+ {
+ if (Configuration.DEBUG)
+ log.fine("About to list all aliases in key store..."); //$NON-NLS-1$
+ writer.println();
+ writer.println(Messages.getFormattedString("ListCmd.24", //$NON-NLS-1$
+ Integer.valueOf(store.size())));
+ for (Enumeration e = store.aliases(); e.hasMoreElements(); )
+ {
+ String anAlias = (String) e.nextElement();
+ if (anAlias != null)
+ list1Alias(anAlias, writer);
+ }
+ }
+ else
+ list1Alias(alias, writer);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.LIST_CMD, true);
+ result.setHeader(Messages.getString("ListCmd.20")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("ListCmd.19")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("ListCmd.18")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("ListCmd.17"), //$NON-NLS-1$
+ Messages.getString("ListCmd.16")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("ListCmd.15"), //$NON-NLS-1$
+ Messages.getString("ListCmd.14")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("ListCmd.13"), //$NON-NLS-1$
+ Messages.getString("ListCmd.12")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("ListCmd.11"), //$NON-NLS-1$
+ Messages.getString("ListCmd.10")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("ListCmd.9"), //$NON-NLS-1$
+ Messages.getString("ListCmd.8")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("ListCmd.7")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ options.add(new Option(Main.RFC_OPT,
+ Messages.getString("ListCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ rfc = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Prints the certificate(s) associated with the designated alias.
+ *
+ * @param anAlias a non-null string denoting an alias in the key-store.
+ * @param writer where to print.
+ * @throws KeyStoreException if an exception occurs while obtaining the
+ * certificate associated to the designated alias.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form of the certificate.
+ * @throws IOException if an I/O related exception occurs during the process.
+ */
+ private void list1Alias(String anAlias, PrintWriter writer)
+ throws KeyStoreException, CertificateEncodingException, IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "list1Alias", anAlias); //$NON-NLS-1$
+ writer.println();
+ writer.println(Messages.getFormattedString("ListCmd.30", anAlias)); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("ListCmd.31", //$NON-NLS-1$
+ store.getCreationDate(anAlias)));
+ if (store.isCertificateEntry(anAlias))
+ {
+ writer.println(Messages.getString("ListCmd.32")); //$NON-NLS-1$
+ Certificate certificate = store.getCertificate(anAlias);
+ print1Certificate(certificate, writer);
+ }
+ else if (store.isKeyEntry(anAlias))
+ {
+ writer.println(Messages.getString("ListCmd.33")); //$NON-NLS-1$
+ Certificate[] chain = store.getCertificateChain(anAlias);
+ print1Chain(chain, writer);
+ }
+ else
+ throw new IllegalArgumentException(Messages.getFormattedString("ListCmd.34", //$NON-NLS-1$
+ anAlias));
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "list1Alias"); //$NON-NLS-1$
+ }
+
+ /**
+ * Prints the designated certificate chain, or a fingerprint of the first
+ * certificate (bottom) in the chain, depending on the values of the flags
+ * <code>v</code> (for verbose) and <code>rfc</code>.
+ * <p>
+ * If both flags are <code>false</code>, only the fingerprint is generated,
+ * otherwise, if the <code>v</code> flag is set, then a human readable output
+ * is generated. If <code>rfc</code> is set, then an RFC-1421 like output
+ * is generated.
+ * <p>Note that both <code>v</code> and <code>rfc</code> cannot both be
+ * <code>true</code> at the same time.
+ *
+ * @param chain the certificate chain to process.
+ * @param writer where to print.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form of the certificate.
+ */
+ private void print1Chain(Certificate[] chain, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ if (! verbose && ! rfc)
+ fingerprint(chain[0], writer);
+ else
+ {
+ int limit = chain.length;
+ writer.println(Messages.getFormattedString("ListCmd.38", //$NON-NLS-1$
+ Integer.valueOf(limit)));
+ writer.println(Messages.getString("ListCmd.39")); //$NON-NLS-1$
+ print1Certificate(chain[0], writer);
+ for (int i = 1; i < limit; i++)
+ {
+ writer.println();
+ writer.println(Messages.getFormattedString("ListCmd.40", //$NON-NLS-1$
+ Integer.valueOf(i + 1)));
+ print1Certificate(chain[i], writer);
+ }
+ writer.println();
+ writer.println(Messages.getString("ListCmd.42")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Prints the designated certificate, or its fingerprint, depending on the
+ * values of the flags <code>v</code> (for verbose) and <code>rfc</code>.
+ * <p>
+ * If both flags are <code>false</code>, only a fingerprint is generated,
+ * otherwise, if the <code>v</code> flag is set, then a human readable output
+ * is generated. If <code>rfc</code> is set, then an RFC-1421 like output
+ * is generated.
+ * <p>Note that both <code>v</code> and <code>rfc</code> cannot both be
+ * <code>true</code> at the same time.
+ *
+ * @param certificate the certificate to process.
+ * @param writer where to print.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form of the certificate.
+ */
+ private void print1Certificate(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ if (verbose)
+ printVerbose(certificate, writer);
+ else if (rfc)
+ printRFC1421(certificate, writer);
+ else
+ fingerprint(certificate, writer);
+ }
+
+ private void printRFC1421(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ byte[] derBytes = certificate.getEncoded();
+ String encoded = Base64.encode(derBytes, 72);
+ writer.println(Messages.getString("ListCmd.43")); //$NON-NLS-1$
+ writer.println(encoded);
+ writer.println(Messages.getString("ListCmd.44")); //$NON-NLS-1$
+ }
+
+ private void fingerprint(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ byte[] derBytes = certificate.getEncoded();
+ String fingerPrint = digestWithMD5(derBytes);
+ writer.println(Messages.getFormattedString("ListCmd.45", fingerPrint)); //$NON-NLS-1$
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/Main.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/Main.java
new file mode 100644
index 000000000..2d5234ad0
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/Main.java
@@ -0,0 +1,329 @@
+/* Main.java -- Implementation of the keytool security tool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.common.ProviderUtil;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.security.Registry;
+import gnu.javax.crypto.jce.GnuCrypto;
+import gnu.javax.security.auth.callback.GnuCallbacks;
+
+import java.util.logging.Logger;
+
+/**
+ * The GNU Classpath implementation of the keytool security tool.
+ * <p>
+ * Except for the <code>-identitydb</code> command, available for importing
+ * JDK 1.1 <i>identities</i> into a key store, this implementation is intended
+ * to be compatible with the behaviour described in the public documentation of
+ * the same tool included in JDK 1.4.
+ */
+public class Main
+{
+ private static final Logger log = Logger.getLogger(Main.class.getName());
+ static final String KEYTOOL_TOOL = "keytool"; //$NON-NLS-1$
+ static final String GENKEY_CMD = "genkey"; //$NON-NLS-1$
+ static final String IMPORT_CMD = "import"; //$NON-NLS-1$
+ static final String SELFCERT_CMD = "selfcert"; //$NON-NLS-1$
+ static final String IDENTITYDB_CMD = "identitydb"; //$NON-NLS-1$
+ static final String CERTREQ_CMD = "certreq"; //$NON-NLS-1$
+ static final String EXPORT_CMD = "export"; //$NON-NLS-1$
+ static final String LIST_CMD = "list"; //$NON-NLS-1$
+ static final String PRINTCERT_CMD = "printcert"; //$NON-NLS-1$
+ static final String KEYCLONE_CMD = "keyclone"; //$NON-NLS-1$
+ static final String STOREPASSWD_CMD = "storepasswd"; //$NON-NLS-1$
+ static final String KEYPASSWD_CMD = "keypasswd"; //$NON-NLS-1$
+ static final String DELETE_CMD = "delete"; //$NON-NLS-1$
+ static final String CACERT_CMD = "cacert"; //$NON-NLS-1$
+
+ static final String _GENKEY = "-" + GENKEY_CMD; //$NON-NLS-1$
+ static final String _IMPORT = "-" + IMPORT_CMD; //$NON-NLS-1$
+ static final String _SELFCERT = "-" + SELFCERT_CMD; //$NON-NLS-1$
+ static final String _IDENTITYDB = "-" + IDENTITYDB_CMD; //$NON-NLS-1$
+ static final String _CERTREQ = "-" + CERTREQ_CMD; //$NON-NLS-1$
+ static final String _EXPORT = "-" + EXPORT_CMD; //$NON-NLS-1$
+ static final String _LIST = "-" + LIST_CMD; //$NON-NLS-1$
+ static final String _PRINTCERT = "-" + PRINTCERT_CMD; //$NON-NLS-1$
+ static final String _KEYCLONE = "-" + KEYCLONE_CMD; //$NON-NLS-1$
+ static final String _STOREPASSWD = "-" + STOREPASSWD_CMD; //$NON-NLS-1$
+ static final String _KEYPASSWD = "-" + KEYPASSWD_CMD; //$NON-NLS-1$
+ static final String _DELETE = "-" + DELETE_CMD; //$NON-NLS-1$
+ static final String _HELP = "-help"; //$NON-NLS-1$
+ static final String _CACERT = "-" + CACERT_CMD; //$NON-NLS-1$
+
+ static final String ALIAS_OPT = "alias"; //$NON-NLS-1$
+ static final String SIGALG_OPT = "sigalg"; //$NON-NLS-1$
+ static final String KEYALG_OPT = "keyalg"; //$NON-NLS-1$
+ static final String KEYSIZE_OPT = "keysize"; //$NON-NLS-1$
+ static final String KEYPASS_OPT = "keypass"; //$NON-NLS-1$
+ static final String VALIDITY_OPT = "validity"; //$NON-NLS-1$
+ static final String STORETYPE_OPT = "storetype"; //$NON-NLS-1$
+ static final String STOREPASS_OPT = "storepass"; //$NON-NLS-1$
+ static final String KEYSTORE_OPT = "keystore"; //$NON-NLS-1$
+ static final String PROVIDER_OPT = "provider"; //$NON-NLS-1$
+ static final String FILE_OPT = "file"; //$NON-NLS-1$
+ static final String VERBOSE_OPT = "v"; //$NON-NLS-1$
+ static final String DEST_OPT = "dest"; //$NON-NLS-1$
+ static final String NEW_OPT = "new"; //$NON-NLS-1$
+ static final String RFC_OPT = "rfc"; //$NON-NLS-1$
+ static final String DNAME_OPT = "dname"; //$NON-NLS-1$
+
+ /** The Preferences key name for the last issued certificate serial nbr. */
+ static final String LAST_SERIAL_NUMBER = "lastSerialNumber"; //$NON-NLS-1$
+ /** Constant denoting the X.509 certificate type. */
+ static final String X_509 = "X.509"; //$NON-NLS-1$
+
+ /** Whether we have already printed the help text or not. */
+ private boolean helpPrinted;
+ /** The new position of GnuCRYPTO provider if it is not already installed. */
+ private int gnuCryptoProviderNdx = -2;
+ /** The new position of GNU Callbacks provider if it is not already installed. */
+ private int gnuCallbacksNdx = -2;
+ /** The command line parser. */
+ private Parser cmdLineParser;
+ /** The shutdown hook. */
+ private ShutdownHook shutdownThread;
+
+ private Main()
+ {
+ super();
+ shutdownThread = new ShutdownHook();
+ Runtime.getRuntime().addShutdownHook(shutdownThread);
+ }
+
+ public static final void main(String[] args)
+ {
+ if (Configuration.DEBUG)
+ log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$
+ Main tool = new Main();
+ int result = 1;
+ try
+ {
+ tool.setup();
+ tool.start(args);
+ result = 0;
+ }
+ catch (OptionException x)
+ {
+ System.err.println(x.getMessage());
+ if (tool.cmdLineParser != null)
+ tool.cmdLineParser.printHelp();
+ }
+ catch (SecurityException x)
+ {
+ if (Configuration.DEBUG)
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getFormattedString("Main.6", //$NON-NLS-1$
+ x.getMessage()));
+ }
+ catch (Exception x)
+ {
+ if (Configuration.DEBUG)
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getFormattedString("Main.8", x)); //$NON-NLS-1$
+ }
+ finally
+ {
+ tool.teardown();
+ if (tool.shutdownThread != null)
+ Runtime.getRuntime().removeShutdownHook(tool.shutdownThread);
+ }
+ if (Configuration.DEBUG)
+ log.exiting(Main.class.getName(), "main", Integer.valueOf(result)); //$NON-NLS-1$
+ System.exit(result);
+ }
+
+ // helper methods -----------------------------------------------------------
+
+ private void setup()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "setup"); //$NON-NLS-1$
+ cmdLineParser = getParser();
+ gnuCryptoProviderNdx = ProviderUtil.addProvider(new GnuCrypto());
+ gnuCallbacksNdx = ProviderUtil.addProvider(new GnuCallbacks());
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "setup"); //$NON-NLS-1$
+ }
+
+ private void start(String[] args) throws Exception
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ if (args == null || args.length == 0)
+ throw new OptionException(""); //$NON-NLS-1$
+
+ String opt;
+ Command cmd;
+ while (args.length > 0)
+ {
+ opt = args[0];
+ cmd = null;
+ if (_GENKEY.equals(opt))
+ cmd = new GenKeyCmd();
+ else if (_IMPORT.equals(opt))
+ cmd = new ImportCmd();
+ else if (_SELFCERT.equals(opt))
+ cmd = new SelfCertCmd();
+ else if (_IDENTITYDB.equals(opt))
+ cmd = new IdentityDBCmd();
+ else if (_CERTREQ.equals(opt))
+ cmd = new CertReqCmd();
+ else if (_EXPORT.equals(opt))
+ cmd = new ExportCmd();
+ else if (_LIST.equals(opt))
+ cmd = new ListCmd();
+ else if (_PRINTCERT.equals(opt))
+ cmd = new PrintCertCmd();
+ else if (_KEYCLONE.equals(opt))
+ cmd = new KeyCloneCmd();
+ else if (_STOREPASSWD.equals(opt))
+ cmd = new StorePasswdCmd();
+ else if (_KEYPASSWD.equals(opt))
+ cmd = new KeyPasswdCmd();
+ else if (_DELETE.equals(opt))
+ cmd = new DeleteCmd();
+ else if (_CACERT.equals(opt))
+ cmd = new CACertCmd();
+ else if (_HELP.equals(opt))
+ throw new OptionException(""); //$NON-NLS-1$
+ else
+ throw new OptionException(Messages.getFormattedString("Main.18", //$NON-NLS-1$
+ opt));
+
+ String[] cmdArgs = new String[args.length - 1];
+ System.arraycopy(args, 1, cmdArgs, 0, cmdArgs.length);
+ args = cmd.processArgs(cmdArgs);
+ cmd.doCommand();
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ private Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(KEYTOOL_TOOL, true);
+ result.setHeader(Messages.getString("Main.19")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("Main.20")); //$NON-NLS-1$
+ OptionGroup cmdGroup = new OptionGroup(Messages.getString("Main.21")); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(GENKEY_CMD,
+ Messages.getString("Main.22"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(IMPORT_CMD,
+ Messages.getString("Main.23"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(SELFCERT_CMD,
+ Messages.getString("Main.24"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(IDENTITYDB_CMD,
+ Messages.getString("Main.25"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(CERTREQ_CMD,
+ Messages.getString("Main.26"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(EXPORT_CMD,
+ Messages.getString("Main.27"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(LIST_CMD,
+ Messages.getString("Main.28"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(PRINTCERT_CMD,
+ Messages.getString("Main.29"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(KEYCLONE_CMD,
+ Messages.getString("Main.30"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(STOREPASSWD_CMD,
+ Messages.getString("Main.31"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(KEYPASSWD_CMD,
+ Messages.getString("Main.32"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(DELETE_CMD,
+ Messages.getString("Main.33"))); //$NON-NLS-1$
+ cmdGroup.add(new NoParseOption(CACERT_CMD,
+ Messages.getString("Main.5"))); //$NON-NLS-1$
+ result.add(cmdGroup);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ void teardown()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ // if we added our own providers remove them
+ if (gnuCryptoProviderNdx > 0)
+ ProviderUtil.removeProvider(Registry.GNU_CRYPTO);
+
+ if (gnuCallbacksNdx > 0)
+ ProviderUtil.removeProvider("GNU-CALLBACKS"); //$NON-NLS-1$
+
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ }
+
+ // Inner class(es)
+ // ==========================================================================
+
+ private class NoParseOption
+ extends Option
+ {
+ public NoParseOption(String name, String description)
+ {
+ super(name, description);
+ }
+
+ public NoParseOption(String name, String description, String param)
+ {
+ super(name, description, param);
+ }
+
+ public void parsed(String argument) throws OptionException
+ {
+ // do nothing
+ }
+ }
+
+ private class ShutdownHook
+ extends Thread
+ {
+ public void run()
+ {
+ teardown();
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/Messages.java
new file mode 100644
index 000000000..ea2825f10
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/Messages.java
@@ -0,0 +1,118 @@
+/* Messages.java -- I18N related helper class
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.logging.Logger;
+
+/**
+ * An initially generated Eclipse helper class to ease the use of localized
+ * messages.
+ * <p>
+ * Enriched to handle localized message formats.
+ */
+class Messages
+{
+ private static final Logger log = Logger.getLogger(Messages.class.getName());
+ private static final String BUNDLE_NAME = "gnu.classpath.tools.keytool.messages";
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+ private static final Map CACHED_FORMATS = new HashMap(5);
+
+ private Messages()
+ {
+ super();
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return constructMessage(key, null);
+ }
+ }
+
+ public static String getFormattedString(String key, Object args)
+ {
+ MessageFormat mf = (MessageFormat) CACHED_FORMATS.get(key);
+ if (mf == null)
+ {
+ String formatString = getString(key);
+ if (formatString.startsWith("!"))
+ return constructMessage(key, args);
+
+ mf = new MessageFormat(formatString);
+ CACHED_FORMATS.put(key, mf);
+ }
+
+ // if the argument is not an array, then build one consisting of the
+ // sole argument before passing it to the format() method
+ try
+ {
+ if (args instanceof Object[])
+ return mf.format(args);
+
+ return mf.format(new Object[] { args });
+ }
+ catch (IllegalArgumentException x)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Exception while rendering a message format keyed by ["
+ + key + "]: " + mf.toPattern());
+ return constructMessage(mf.toPattern(), args);
+ }
+ }
+
+ private static final String constructMessage(String m, Object args)
+ {
+ if (args == null)
+ return '!' + m + '!';
+
+ return '!' + m + '!' + String.valueOf(args) + '!';
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/PrintCertCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/PrintCertCmd.java
new file mode 100644
index 000000000..cb9d03513
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/PrintCertCmd.java
@@ -0,0 +1,143 @@
+/* PrintCertCmd.java -- The printcert command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.PrintWriter;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.logging.Logger;
+
+/**
+ * The <b>-printcert</b> keytool command handler is used to read a certificate
+ * from a designated file, and print its contents in a human-readable format.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the file to read the certificate from.
+ * If this option is omitted, the tool will process STDIN.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class PrintCertCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(PrintCertCmd.class.getName());
+ protected String _certFileName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certFileName = pathName;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_certFileName);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-printcert handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -file=" + _certFileName); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.entering(getClass().getName(), "start"); //$NON-NLS-1$
+ CertificateFactory x509Factory = CertificateFactory.getInstance(Main.X_509);
+ Certificate certificate = x509Factory.generateCertificate(inStream);
+ PrintWriter writer = new PrintWriter(System.out, true);
+ writer.println();
+ printVerbose(certificate, writer);
+ if (Configuration.DEBUG)
+ log.exiting(getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.PRINTCERT_CMD, true);
+ result.setHeader(Messages.getString("PrintCertCmd.5")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("PrintCertCmd.6")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("PrintCertCmd.7")); //$NON-NLS-1$
+ options.add(new Option(Main.FILE_OPT,
+ Messages.getString("PrintCertCmd.8"), //$NON-NLS-1$
+ Messages.getString("PrintCertCmd.9")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _certFileName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("PrintCertCmd.10")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/SelfCertCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/SelfCertCmd.java
new file mode 100644
index 000000000..395bfe2cd
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/SelfCertCmd.java
@@ -0,0 +1,440 @@
+/* SelfCertCmd.java -- The selfcert command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.security.x509.X500DistinguishedName;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The <b>-selfcert</b> keytool command handler is used to generate a self-
+ * signed X.509 version 1 certificate using key store credentials stored under a
+ * designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-sigalg ALGORITHM</dt>
+ * <dd>The canonical name of the digital signature algorithm to use for
+ * signing the certificate. If this option is omitted, a default value will
+ * be chosen based on the type of the private key associated with the
+ * designated <i>Alias</i>. If the private key is a <code>DSA</code> one,
+ * the value for the signature algorithm will be <code>SHA1withDSA</code>.
+ * If on the other hand the private key is an <code>RSA</code> one, then
+ * the tool will use <code>MD5withRSA</code> as the signature algorithm.
+ * <p></dd>
+ *
+ * <dt>-dname NAME</dt>
+ * <dd>Use this option to specify the <i>Distinguished Name</i> of the
+ * newly generated self-signed certificate. If this option is omitted, the
+ * existing <i>Distinguished Name</i> of the base certificate in the chain
+ * associated with the designated <i>Alias</i> will be used instead.
+ * <p>
+ * The syntax of a valid value for this option MUST follow RFC-2253
+ * specifications. Namely the following components (with their accepted
+ * meaning) will be recognized. Note that the component name is case-
+ * insensitive:
+ * <dl>
+ * <dt>CN</dt>
+ * <dd>The Common Name; e.g. "host.domain.com"</dd>
+ *
+ * <dt>OU</dt>
+ * <dd>The Organizational Unit; e.g. "IT Department"</dd>
+ *
+ * <dt>O</dt>
+ * <dd>The Organization Name; e.g. "The Sample Company"</dd>
+ *
+ * <dt>L</dt>
+ * <dd>The Locality Name; e.g. "Sydney"</dd>
+ *
+ * <dt>ST</dt>
+ * <dd>The State Name; e.g. "New South Wales"</dd>
+ *
+ * <dt>C</dt>
+ * <dd>The 2-letter Country identifier; e.g. "AU"</dd>
+ * </dl>
+ * <p>
+ * When specified with a <code>-dname</code> option, each pair of component
+ * / value will be separated from the other with a comma. Each component
+ * and value pair MUST be separated by an equal sign. For example, the
+ * following is a valid DN value:
+ * <pre>
+ * CN=host.domain.com, O=The Sample Company, L=Sydney, ST=NSW, C=AU
+ * </pre>
+ * <p></dd>
+ *
+ * <dt>-validity DAY_COUNT</dt>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class SelfCertCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(SelfCertCmd.class.getName());
+ protected String _alias;
+ protected String _sigAlgorithm;
+ protected String _dName;
+ protected String _password;
+ protected String _validityStr;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ private X500DistinguishedName distinguishedName;
+ private int validityInDays;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /**
+ * @param algorithm the canonical name of the digital signature algorithm to
+ * use.
+ */
+ public void setSigalg(String algorithm)
+ {
+ this._sigAlgorithm = algorithm;
+ }
+
+ /**
+ * @param name the distiniguished name of both the issuer and subject (since
+ * we are dealing with a self-signed certificate) to use.
+ */
+ public void setDname(String name)
+ {
+ this._dName = name;
+ }
+
+ /**
+ * @param days the string representation of the number of days (a decimal,
+ * positive integer) to assign to the generated (self-signed)
+ * certificate.
+ */
+ public void setValidity(String days)
+ {
+ this._validityStr = days;
+ }
+
+ /** @param password the (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+ setValidityParam(_validityStr);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-selfcert handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -alias=" + alias); //$NON-NLS-1$
+ log.fine(" -sigalg=" + _sigAlgorithm); //$NON-NLS-1$
+ log.fine(" -dname=" + _dName); //$NON-NLS-1$
+ log.fine(" -validity=" + validityInDays); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException, IOException, UnsupportedCallbackException,
+ InvalidKeyException, SignatureException, CertificateException
+ {
+ if (Configuration.DEBUG)
+ log.entering(getClass().getName(), "start"); //$NON-NLS-1$
+ // 1. get the key entry and certificate chain associated to alias
+ Key privateKey = getAliasPrivateKey();
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ // 2. if the user has not supplied a DN use one from the certificate chain
+ X509Certificate bottomCertificate = (X509Certificate) chain[0];
+ X500Principal defaultPrincipal = bottomCertificate.getIssuerX500Principal();
+ setDName(_dName, defaultPrincipal);
+
+ // 4. get alias's public key from certificate's SubjectPublicKeyInfo
+ PublicKey publicKey = bottomCertificate.getPublicKey();
+
+ // 5. issue the self-signed certificate
+ setSignatureAlgorithmParam(_sigAlgorithm, privateKey);
+
+ byte[] derBytes = getSelfSignedCertificate(distinguishedName,
+ publicKey,
+ (PrivateKey) privateKey);
+ CertificateFactory x509Factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+ ByteArrayInputStream bais = new ByteArrayInputStream(derBytes);
+ Certificate certificate = x509Factory.generateCertificate(bais);
+
+ // 6. store it, w/ its private key, associating them to alias
+ chain = new Certificate[] { certificate };
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, chain);
+
+ // 7. persist the key store
+ saveKeyStore();
+ if (Configuration.DEBUG)
+ log.exiting(getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.SELFCERT_CMD, true);
+ result.setHeader(Messages.getString("SelfCertCmd.14")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("SelfCertCmd.15")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("SelfCertCmd.16")); //$NON-NLS-1$
+ options.add(new Option(Main.ALIAS_OPT,
+ Messages.getString("SelfCertCmd.17"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.18")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _alias = argument;
+ }
+ });
+ options.add(new Option(Main.SIGALG_OPT,
+ Messages.getString("SelfCertCmd.19"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.20")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _sigAlgorithm = argument;
+ }
+ });
+ options.add(new Option(Main.DNAME_OPT,
+ Messages.getString("SelfCertCmd.21"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.22")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _dName = argument;
+ }
+ });
+ options.add(new Option(Main.KEYPASS_OPT,
+ Messages.getString("SelfCertCmd.23"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.24")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _password = argument;
+ }
+ });
+ options.add(new Option(Main.VALIDITY_OPT,
+ Messages.getString("SelfCertCmd.25"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.26")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _validityStr = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("SelfCertCmd.27"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.28")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("SelfCertCmd.29"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.30")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("SelfCertCmd.31"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.32")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("SelfCertCmd.33"), //$NON-NLS-1$
+ Messages.getString("SelfCertCmd.34")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("SelfCertCmd.35")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ private void setDName(String name, X500Principal defaultName)
+ {
+ if (name != null && name.trim().length() > 0)
+ name = name.trim();
+ else
+ {
+ // If dname is supplied at the command line, it is used as the X.500
+ // Distinguished Name for both the issuer and subject of the certificate.
+ // Otherwise, the X.500 Distinguished Name associated with alias (at the
+ // bottom of its existing certificate chain) is used.
+ name = defaultName.toString().trim();
+ }
+
+ distinguishedName = new X500DistinguishedName(name);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java b/libjava/classpath/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java
new file mode 100644
index 000000000..24a4b0fa1
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java
@@ -0,0 +1,318 @@
+/* StorePasswdCmd.java -- The storepasswd command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.Configuration;
+import gnu.classpath.SystemProperties;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-storepasswd</b> keytool command handler is used to change the
+ * password which protects the integrity of the key store.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-new PASSWORD</dt>
+ * <dd>The new, and different, password which will be used to protect the
+ * designated key store.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYPE</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class StorePasswdCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(StorePasswdCmd.class.getName());
+ protected String _newPassword;
+ protected String _ksType;
+ protected String _ksURL;
+ protected String _ksPassword;
+ protected String _providerClassName;
+ private char[] newStorePasswordChars;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param password the new key-store password to use. */
+ public void setNew(String password)
+ {
+ this._newPassword = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setNewKeystorePassword(_newPassword);
+ if (Configuration.DEBUG)
+ {
+ log.fine("-storepasswd handler will use the following options:"); //$NON-NLS-1$
+ log.fine(" -storetype=" + storeType); //$NON-NLS-1$
+ log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.fine(" -provider=" + provider); //$NON-NLS-1$
+ log.fine(" -v=" + verbose); //$NON-NLS-1$
+ }
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ CertificateException, IOException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+ saveKeyStore(newStorePasswordChars);
+ if (Configuration.DEBUG)
+ log.exiting(getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ Parser getParser()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
+ Parser result = new ClasspathToolParser(Main.STOREPASSWD_CMD, true);
+ result.setHeader(Messages.getString("StorePasswdCmd.18")); //$NON-NLS-1$
+ result.setFooter(Messages.getString("StorePasswdCmd.17")); //$NON-NLS-1$
+ OptionGroup options = new OptionGroup(Messages.getString("StorePasswdCmd.16")); //$NON-NLS-1$
+ options.add(new Option(Main.NEW_OPT,
+ Messages.getString("StorePasswdCmd.15"), //$NON-NLS-1$
+ Messages.getString("StorePasswdCmd.8")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _newPassword = argument;
+ }
+ });
+ options.add(new Option(Main.STORETYPE_OPT,
+ Messages.getString("StorePasswdCmd.13"), //$NON-NLS-1$
+ Messages.getString("StorePasswdCmd.12")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksType = argument;
+ }
+ });
+ options.add(new Option(Main.KEYSTORE_OPT,
+ Messages.getString("StorePasswdCmd.11"), //$NON-NLS-1$
+ Messages.getString("StorePasswdCmd.10")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksURL = argument;
+ }
+ });
+ options.add(new Option(Main.STOREPASS_OPT,
+ Messages.getString("StorePasswdCmd.9"), //$NON-NLS-1$
+ Messages.getString("StorePasswdCmd.8")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _ksPassword = argument;
+ }
+ });
+ options.add(new Option(Main.PROVIDER_OPT,
+ Messages.getString("StorePasswdCmd.7"), //$NON-NLS-1$
+ Messages.getString("StorePasswdCmd.6")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ _providerClassName = argument;
+ }
+ });
+ options.add(new Option(Main.VERBOSE_OPT,
+ Messages.getString("StorePasswdCmd.5")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ result.add(options);
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
+ return result;
+ }
+
+ protected void setNewKeystorePassword(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null)
+ newStorePasswordChars = password.toCharArray();
+ else
+ {
+ boolean ok = false;
+ Callback[] prompts = new Callback[1];
+ Callback[] errors = new Callback[1];
+ for (int i = 0; i < 3; i++)
+ if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
+ {
+ ok = true;
+ break;
+ }
+ if (! ok)
+ throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
+ }
+ }
+
+ private boolean prompt4NewPassword(CallbackHandler handler,
+ Callback[] prompts, Callback[] errors)
+ throws IOException, UnsupportedCallbackException
+ {
+ // prompt user (1st time) to provide one
+ String p = Messages.getString("StorePasswdCmd.20"); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd1 = pcb.getPassword();
+ pcb.clearPassword();
+ String ls = SystemProperties.getProperty("line.separator"); //$NON-NLS-1$
+ if (pwd1 == null || pwd1.length < 6)
+ {
+ String m = Messages.getString("StorePasswdCmd.21") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ if (Arrays.equals(storePasswordChars, pwd1))
+ {
+ String m = Messages.getString("StorePasswdCmd.22") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ // prompt user (2nd time) for confirmation
+ pcb = new PasswordCallback(Messages.getString("StorePasswdCmd.23"), false); //$NON-NLS-1$
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd2 = pcb.getPassword();
+ pcb.clearPassword();
+ if (! Arrays.equals(pwd1, pwd2))
+ {
+ String m = Messages.getString("StorePasswdCmd.24") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ newStorePasswordChars = pwd2;
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/native2ascii/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/native2ascii/Messages.java
new file mode 100644
index 000000000..4c6bae4dc
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/native2ascii/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- translation support for native2ascii
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.native2ascii;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.native2ascii.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/native2ascii/Native2ASCII.java b/libjava/classpath/tools/gnu/classpath/tools/native2ascii/Native2ASCII.java
new file mode 100644
index 000000000..524796d3b
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/native2ascii/Native2ASCII.java
@@ -0,0 +1,194 @@
+/* Native2ASCII.java - native2ascii program
+ Copyright (C) 2003, 2007, 2008 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.native2ascii;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+/**
+ * Native2ASCII main program.
+ * @author Ito Kazumitsu <kaz@maczuka.gcd.org>
+ */
+public class Native2ASCII
+{
+ // Input file.
+ String input;
+ // Output file.
+ String output;
+ // Encoding to use.
+ String encoding;
+ // True for reverse operation.
+ boolean reversed;
+
+ private class HandleFile extends FileArgumentCallback
+ {
+ public HandleFile()
+ {
+ }
+
+ public void notifyFile(String fileArgument)
+ throws OptionException
+ {
+ if (input == null)
+ input = fileArgument;
+ else if (output == null)
+ output = fileArgument;
+ else
+ throw new OptionException(Messages.getString("Native2ASCII.TooManyFiles")); //$NON-NLS-1$
+ }
+ }
+
+ private Parser createParser()
+ {
+ Parser result = new ClasspathToolParser("native2ascii", true); //$NON-NLS-1$
+ result.setHeader(Messages.getString("Native2ASCII.Usage")); //$NON-NLS-1$
+
+ result.add(new Option("encoding", Messages.getString("Native2ASCII.EncodingHelp"), Messages.getString("Native2ASCII.EncodingArgName")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ if (encoding != null)
+ throw new OptionException(Messages.getString("Native2ASCII.EncodingSpecified")); //$NON-NLS-1$
+ encoding = argument;
+ }
+ });
+ result.add(new Option("reverse", Messages.getString("Native2ASCII.ReverseHelp")) //$NON-NLS-1$ //$NON-NLS-2$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ reversed = true;
+ }
+ });
+
+ // We mistakenly added the extra "d" in "reversed"; now we don't
+ // want to remove it, for backward compatibility.
+ result.add(new Option("reversed", Messages.getString("Native2ASCII.ReversedHelpCompat")) //$NON-NLS-1$ //$NON-NLS-2$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ reversed = true;
+ }
+ });
+
+ return result;
+ }
+
+ private void run(String[] args)
+ {
+ Parser argParser = createParser();
+ argParser.parse(args, new HandleFile());
+
+ if (encoding == null)
+ encoding = System.getProperty("file.encoding"); //$NON-NLS-1$
+ try
+ {
+ InputStream is = (input == null ? System.in
+ : new FileInputStream(input));
+ OutputStream os = (output == null ? (OutputStream) System.out
+ : new FileOutputStream(output));
+
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(is,
+ encoding));
+ PrintWriter wtr = new PrintWriter(
+ new BufferedWriter(
+ new OutputStreamWriter(
+ os,
+ encoding)));
+ while (true)
+ {
+ String s = rdr.readLine();
+ if (s == null)
+ break;
+ StringBuilder sb = new StringBuilder(s.length() + 80);
+ for (int i = 0; i < s.length(); i++)
+ {
+ char c = s.charAt(i);
+ if (reversed
+ && i + 6 <= s.length()
+ && s.charAt(i) == '\\'
+ && s.charAt(i + 1) == 'u')
+ {
+ int num = Integer.parseInt(s.substring(i + 2, i + 6), 16);
+ sb.append((char) num);
+ i += 5;
+ }
+ else if ((int)c <= 127 || reversed)
+ {
+ sb.append(c);
+ }
+ else
+ {
+ sb.append("\\u"); //$NON-NLS-1$
+ if ((int)c <= 0xff)
+ sb.append("00"); //$NON-NLS-1$
+ else if ((int)c <= 0xfff)
+ sb.append("0"); //$NON-NLS-1$
+ sb.append(Integer.toHexString((int) c));
+ }
+ }
+ wtr.println(sb.toString());
+ }
+ rdr.close();
+ wtr.flush();
+ wtr.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ new Native2ASCII().run(args);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/orbd/Main.java b/libjava/classpath/tools/gnu/classpath/tools/orbd/Main.java
new file mode 100644
index 000000000..7e970adfb
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/orbd/Main.java
@@ -0,0 +1,226 @@
+/* NamingServicePersistent.java -- The persistent naming service.
+ Copyright (C) 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.orbd;
+
+import gnu.CORBA.OrbFunctional;
+import gnu.CORBA.IOR;
+import gnu.CORBA.NamingService.Ext;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+import org.omg.CosNaming.NamingContextExt;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * The server for the GNU Classpath persistent naming service.
+ *
+ * GNU Classpath currently works with this naming service and is also
+ * interoperable with the Sun Microsystems naming services from releases 1.3 and
+ * 1.4, both transient <i>tnameserv</i> and persistent <i>orbd</i>.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Main
+{
+ /**
+ * The default port (900), on that the naming service starts if no
+ * -ORBInitialPort is specified in the command line.
+ */
+ public static final int PORT = 900;
+
+ private int port = PORT;
+ private String iorf;
+ private boolean cold;
+ private String directory = "";
+
+ /**
+ * Get the object key for the naming service. The default key is the string
+ * "NameService" in ASCII.
+ *
+ * @return the byte array.
+ */
+ public static byte[] getDefaultKey()
+ {
+ try
+ { // NameService
+ return "NameService".getBytes("UTF-8");
+ }
+ catch (UnsupportedEncodingException ex)
+ {
+ throw new InternalError("UTF-8 unsupported");
+ }
+ }
+
+ private Parser initializeParser()
+ {
+ Parser parser = new ClasspathToolParser("orbd", true); //$NON-NLS-1$
+ parser.setHeader(Messages.getString("Main.Usage")); //$NON-NLS-1$
+
+ parser.add(new Option("ORBInitialPort", //$NON-NLS-1$
+ Messages.getString("Main.ORBInitialPort"), //$NON-NLS-1$
+ Messages.getString("Main.Port")) //$NON-NLS-1$
+ {
+ public void parsed(String portArgument) throws OptionException
+ {
+ port = Integer.parseInt(portArgument);
+ }
+ });
+
+ parser.add(new Option("ior", //$NON-NLS-1$
+ Messages.getString("Main.IOR"), //$NON-NLS-1$
+ Messages.getString("Main.IORFile")) //$NON-NLS-1$
+ {
+ public void parsed(String fileArgument) throws OptionException
+ {
+ iorf = fileArgument;
+ }
+ });
+ parser.add(new Option("directory", //$NON-NLS-1$
+ Messages.getString("Main.Directory"), //$NON-NLS-1$
+ Messages.getString("Main.DirectoryArgument")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ directory = argument;
+ }
+ });
+ parser.add(new Option("restart", //$NON-NLS-1$
+ Messages.getString("Main.Restart")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ cold = true;
+ }
+ });
+
+ return parser;
+ }
+
+ private void run(String[] args)
+ {
+ Parser parser = initializeParser();
+ parser.parse(args);
+
+ try
+ {
+ // Create and initialize the ORB
+ final OrbFunctional orb = new OrbFunctional();
+ OrbFunctional.setPort(port);
+
+ // Create the servant and register it with the ORB
+ File dataDirectory = new File(directory);
+ System.out.println("Persistent data stored at "
+ + dataDirectory.getAbsolutePath());
+ dataDirectory.mkdirs();
+
+ // / TODO support more starting modes.
+ NamingContextExt namer = new Ext(
+ new PersistentContext(
+ orb,
+ dataDirectory,
+ cold));
+
+ // Case with the key "NameService".
+ orb.connect(namer, "NameService".getBytes());
+
+ // Storing the IOR reference.
+ String ior = orb.object_to_string(namer);
+ IOR iorr = IOR.parse(ior);
+ if (iorf != null)
+ {
+ FileOutputStream f = new FileOutputStream(iorf);
+ PrintStream p = new PrintStream(f);
+ p.print(ior);
+ p.close();
+ }
+
+ System.out.println("GNU Classpath persistent naming service "
+ + "started at " + iorr.Internet.host + ":"
+ + iorr.Internet.port + " key 'NameService'.\n\n"
+ + "Copyright (C) 2011 Free Software Foundation\n"
+ + "This tool comes with ABSOLUTELY NO WARRANTY. "
+ + "This is free software, and you are\nwelcome to "
+ + "redistribute it under conditions, defined in "
+ + "GNU Classpath license.\n\n" + ior);
+
+ new Thread()
+ {
+ public void run()
+ {
+ // Wait for invocations from clients.
+ orb.run();
+ }
+ }.start();
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+ finally
+ {
+ // Restore the default value for allocating ports for the subsequent
+ // objects.
+ OrbFunctional.setPort(OrbFunctional.DEFAULT_INITIAL_PORT);
+ }
+ }
+
+ /**
+ * The persistent naming service entry point.
+ */
+ public static void main(String[] args)
+ {
+ Main orbdprogram = new Main();
+ try
+ {
+ orbdprogram.run(args);
+ }
+ catch (Exception e)
+ {
+ System.err.println(Messages.getString("Main.InternalError")); //$NON-NLS-1$
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/orbd/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/orbd/Messages.java
new file mode 100644
index 000000000..c9bb371ad
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/orbd/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- localization support for orbd
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.orbd;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.orbd.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContext.java b/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContext.java
new file mode 100644
index 000000000..4526813b8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContext.java
@@ -0,0 +1,152 @@
+/* PersistentContext.java -- The persistent naming context.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.orbd;
+
+import gnu.CORBA.NamingService.NameTransformer;
+import gnu.CORBA.NamingService.TransientContext;
+
+import java.io.File;
+
+import org.omg.CORBA.ORB;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContext;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+
+/**
+ * This class implements the persistent naming service, defined by
+ * {@link NamingContext}. The 'persistent' means that the service remembers the
+ * mappings, stored between restarts.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class PersistentContext
+ extends TransientContext
+{
+ /**
+ * Use serial version UID for interoperability.
+ */
+ private static final long serialVersionUID = 2;
+
+ /**
+ * The folder, where the persistent context information is stored.
+ */
+ File contextFolder;
+
+ /**
+ * The uinque context identifier.
+ */
+ static long num = System.currentTimeMillis();
+
+ /**
+ * The naming service orb.
+ */
+ ORB orb;
+
+ /**
+ * Create the persistent naming context that will store the files in the given
+ * folder of the local file system. This method also connects object to the
+ * passed ORB.
+ *
+ * @param an_orb the naming service ORB, used to obtain and produce the object
+ * stringified references.
+ * @param folder the folder, where the persistent information is stored.
+ * @param reset if true, the previous naming data are discarded. If false
+ * (normally expected), they are loaded from the persistent memory to
+ * provide the persistence.
+ */
+ public PersistentContext(ORB an_orb, File folder, boolean reset)
+ {
+ super(
+ new PersistentContextMap(an_orb, new File(folder, "contexts.txt"), reset),
+ new PersistentMap(an_orb, new File(folder, "objects.txt"), reset));
+ contextFolder = folder;
+ folder.mkdirs();
+ orb = an_orb;
+ orb.connect(this);
+ }
+
+ /**
+ * Get the unique context number;
+ *
+ * @return the context number
+ */
+ static synchronized String getNum()
+ {
+ return Long.toHexString(num++);
+ }
+
+ /**
+ * Create new persistent context.
+ */
+ public NamingContext new_context()
+ {
+ File ctxFolder = new File(contextFolder, "ctx_"+getNum());
+ return new PersistentContext(orb, ctxFolder, true);
+ }
+
+ /**
+ * Create a new context and give it a given name (bound it) in the current
+ * context. The method benefits from passing the better readable context name.
+ *
+ * @param a_name the name being given to the new context.
+ * @return the newly created context.
+ * @throws AlreadyBound if the name is already in use.
+ * @throws InvalidName if the name has zero length or otherwise invalid.
+ */
+ public NamingContext bind_new_context(NameComponent[] a_name)
+ throws NotFound, AlreadyBound, CannotProceed, InvalidName
+ {
+ if (named_contexts.containsKey(a_name[0])
+ || named_objects.containsKey(a_name[0]))
+ throw new AlreadyBound();
+
+ NameTransformer transformer = new NameTransformer();
+
+ File ctxFolder = new File(contextFolder,
+ transformer.toString(a_name).replace('/', '.')
+ + ".v" + getNum());
+
+ NamingContext child = new PersistentContext(orb, ctxFolder, true);
+ bind_context(a_name, child);
+ return child;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContextMap.java b/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContextMap.java
new file mode 100644
index 000000000..d83f2bf4c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentContextMap.java
@@ -0,0 +1,87 @@
+/* PersistentContextMap.java -- The persistent context naming map
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.orbd;
+
+import java.io.File;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Object;
+
+/**
+ * The persistent context naming map for the persistent naming service.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class PersistentContextMap extends PersistentMap
+{
+ /**
+ * Create the persistent context map that stores information in the given
+ * file.
+ *
+ * @param an_orb the naming service ORB, used to obtain and produce the object
+ * stringified references.
+ * @param mapFile the file, where the persistent information is stored.
+ * @param reset if true, the previous naming data are discarded. If false
+ * (normally expected), they are loaded from the persistent memory to
+ * provide the persistence.
+ */
+ public PersistentContextMap(ORB an_orb, File mapFile, boolean reset)
+ {
+ super(an_orb, mapFile, reset);
+ }
+
+ /**
+ * This method expects the PersistentContext as its parameter. The returned
+ * description line is the name of the context parent folder.
+ */
+ protected String object_to_string(Object object)
+ {
+ PersistentContext pc = (PersistentContext) object;
+ return pc.contextFolder.getAbsolutePath();
+ }
+
+ /**
+ * This method restores the PersistenContext. The description line is
+ * interpreted as the folder name, absolute path.
+ */
+ protected Object string_to_object(String description)
+ {
+ return new PersistentContext(orb, new File(description), reset);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentMap.java b/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentMap.java
new file mode 100644
index 000000000..a39ff28ba
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/orbd/PersistentMap.java
@@ -0,0 +1,454 @@
+/* PersistentMap.java -- The persistent object naming map
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.orbd;
+
+import gnu.CORBA.NamingService.NamingMap;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.omg.CORBA.ORB;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+
+/**
+ * The persistent object naming map for the persistent naming service. The
+ * inherited (super.) naming map implementation is transient and is used as a
+ * cache. During the normal work, the naming map does not read from the disk,
+ * just stores the changes there. Map only reads from the disk when it starts.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class PersistentMap
+ extends NamingMap
+{
+ /**
+ * The data entry.
+ */
+ public static class Entry
+ {
+ String id;
+
+ String kind;
+
+ String ior;
+
+ /**
+ * Get the name component node.
+ */
+ public NameComponent getComponent()
+ {
+ return new NameComponent(id, kind);
+ }
+
+ /**
+ * Write the naming map entry to the output stream.
+ */
+ public void write(OutputStream out) throws IOException
+ {
+ // Format: id.kind <eoln> ior <eoln><eoln>
+ out.write(getKey(id, kind).getBytes());
+ out.write('\n');
+ out.write(ior.getBytes());
+ out.write('\n');
+ out.close();
+ }
+
+ /**
+ * Read the name component from the input stream
+ */
+ public boolean read(BufferedReader in) throws IOException
+ {
+ String key = in.readLine();
+ String xior = in.readLine();
+
+ if (key != null && xior != null)
+ {
+ if (key.length() < 2)
+ {
+ // A single char key cannot have the kind part.
+ id = key;
+ kind = "";
+ }
+ else
+ {
+ // Search for the id/kind splitter, dot:
+ int iks = - 1;
+ for (int i = 1; i < key.length(); i++)
+ {
+ if (key.charAt(i) == '.')
+ // The id is separated from kind by dot, unless preceeded by
+ // the
+ // escape character, \.
+ if (key.charAt(i - 1) != '\\')
+ {
+ iks = i;
+ break;
+ }
+ }
+
+ // May also end by dot, if the kind field is missing.
+ if (iks < 0)
+ {
+ id = key;
+ kind = "";
+ }
+ else if (iks == key.length() - 1)
+ {
+ id = key.substring(0, key.length() - 1);
+ kind = "";
+ }
+ else
+ {
+ id = key.substring(0, iks);
+ kind = key.substring(iks + 1);
+ }
+ }
+ ior = xior;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Get the key value from the name component.
+ *
+ * @param id the component id
+ * @param kind the component kind
+ * @return the key value
+ */
+ public String getKey(String id, String kind)
+ {
+ StringBuilder b = new StringBuilder(id.length() + 8);
+ appEscaping(b, id);
+ b.append('.');
+ if (kind != null && kind.length() > 0)
+ appEscaping(b, kind);
+ return b.toString();
+ }
+
+ /**
+ * Append the contents of the string to this string buffer, inserting the
+ * escape sequences, where required.
+ *
+ * @param b a buffer to append the contents to.
+ * @param s a string to append.
+ */
+ void appEscaping(StringBuilder b, String s)
+ {
+ char c;
+ for (int i = 0; i < s.length(); i++)
+ {
+ c = s.charAt(i);
+ switch (c)
+ {
+ case '.':
+ case '/':
+ case '\\':
+ b.append('\\');
+ b.append(c);
+ break;
+
+ default:
+ b.append(c);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * The file, where the persistent naming map stores the information. The
+ * format of this file is n*(id LF kind LF ior LFLF).
+ */
+ public final File file;
+
+ /**
+ * The naming service ORB, used to obtain and produce the object stringified
+ * references.
+ */
+ ORB orb;
+
+ /**
+ * If true, all existing data on the file system are discarded.
+ */
+ boolean reset;
+
+ /**
+ * Create the persistent map that stores information in the given file.
+ *
+ * @param an_orb the naming service ORB, used to obtain and produce the object
+ * stringified references.
+ * @param mapFile the file, where the persistent information is stored.
+ * @param a_reset if true, the previous naming data are discarded. If false
+ * (normally expected), they are loaded from the persistent memory to
+ * provide the persistence.
+ */
+ public PersistentMap(ORB an_orb, File mapFile, boolean a_reset)
+ {
+ super();
+ orb = an_orb;
+ file = mapFile;
+ reset = a_reset;
+
+ // Initialise the persistent map with existing data.
+ if (file.exists() && ! reset)
+ {
+
+ BufferedReader in;
+ try
+ {
+ FileInputStream fin = new FileInputStream(file);
+ in = new BufferedReader(new InputStreamReader(fin));
+ Entry e = new Entry();
+ boolean ok;
+
+ while (e.read(in))
+ {
+ org.omg.CORBA .Object object = string_to_object(e.ior);
+ orb.connect(object);
+ map.put(e.getComponent(), object);
+ }
+ }
+ catch (Exception ex)
+ {
+ InternalError ierr = new InternalError(file.getAbsolutePath());
+ ierr.initCause(ex);
+ throw ierr;
+ }
+ }
+ }
+
+ /**
+ * Restore object from its string description.
+ *
+ * @param description the string, describing the object
+ *
+ * @return the object.
+ */
+ protected org.omg.CORBA.Object string_to_object(String description)
+ {
+ return orb.string_to_object(description);
+ }
+
+ /**
+ * Convert the object to its string description
+ *
+ * @param object the object to convert
+ * @return the string description of the object
+ */
+ protected String object_to_string(org.omg.CORBA .Object object)
+ {
+ return orb.object_to_string(object);
+ }
+
+ /**
+ * Put the given GIOP object, specifying the given name as a key. If the entry
+ * with the given name already exists, or if the given object is already
+ * mapped under another name, the {@link AlreadyBound} exception will be
+ * thrown.
+ *
+ * @param name the name
+ * @param object the object
+ */
+ public void bind(NameComponent name, org.omg.CORBA.Object object)
+ throws AlreadyBound, InvalidName
+ {
+ if (!containsKey(name))
+ {
+ super.bind(name, object);
+ register(name, object);
+ }
+ else
+ throw new AlreadyBound(name.id + "." + name.kind);
+ }
+
+ /**
+ * Put the given CORBA object, specifying the given name as a key. Remove all
+ * pre - existing mappings for the given name and object.
+ *
+ * @param name the name.
+ * @param object the object
+ */
+ public void rebind(NameComponent name, org.omg.CORBA.Object object)
+ throws InvalidName
+ {
+ if (containsKey(name))
+ {
+ org.omg.CORBA.Object existing = get(name);
+ String ior = object_to_string(object);
+ String xior = object_to_string(existing);
+
+ // Same name and same ior - nothing to do.
+ if (ior.equals(xior))
+ return;
+ else
+ remove(name);
+ }
+
+ Iterator iter = entries().iterator();
+ Map.Entry item;
+
+ // Remove the existing mapping for the given object, if present.
+ while (iter.hasNext())
+ {
+ item = (Map.Entry) iter.next();
+ if (item.getValue().equals(object))
+ iter.remove();
+ }
+
+ map.put(name, object);
+ register(name, object);
+ }
+
+ /**
+ * Removes the given name, if present.
+ *
+ * @param name a name to remove.
+ */
+ public void remove(NameComponent name)
+ {
+ super.remove(name);
+ unregister(name);
+ }
+
+ /**
+ * Register this name - object pair in the persistent storage.
+ *
+ * @param name the name.
+ * @param object the object
+ */
+ public void register(NameComponent name, org.omg.CORBA.Object object)
+ {
+ // If this key is already known, and this is the same object,
+ // then return without action.
+ String ior = object_to_string(object);
+
+ synchronized (file)
+ {
+ try
+ {
+ FileOutputStream fou;
+
+ if (! file.exists())
+ fou = new FileOutputStream(file);
+ else
+ fou = new FileOutputStream(file, true);
+
+ Entry e = new Entry();
+ e.id = name.id;
+ e.kind = name.kind;
+ e.ior = ior;
+ e.write(fou);
+ fou.close();
+ }
+ catch (Exception e)
+ {
+ InternalError ierr = new InternalError(file.getAbsolutePath());
+ ierr.initCause(e);
+ throw ierr;
+ }
+ }
+ }
+
+ /**
+ * Remove this name from the persistent storage.
+ *
+ * @param name the name to remove
+ */
+ public void unregister(NameComponent name)
+ {
+ synchronized (file)
+ {
+ try
+ {
+ File nf = new File(file.getParent(), file.getName() + "_t");
+ FileInputStream fin = new FileInputStream(file);
+ FileOutputStream fou = new FileOutputStream(nf);
+ BufferedOutputStream ou = new BufferedOutputStream(fou);
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(fin));
+ String s;
+ String nk = name.kind;
+ if (nk == null)
+ nk = "";
+
+ Entry e = new Entry();
+
+ while (e.read(in))
+ {
+ if (e.id.equals(name.id) && e.kind.equals(nk))
+ {
+ // Do nothing - skip.
+ }
+ else
+ {
+ e.write(ou);
+ }
+ }
+
+ File deleteIt = new File(file.getParent(), file.getName() + "_d");
+ if (deleteIt.exists())
+ deleteIt.delete();
+
+ if (! file.renameTo(deleteIt))
+ throw new IOException(file.getAbsolutePath() + " rename failed");
+
+ if (! nf.renameTo(file))
+ throw new IOException(file.getAbsolutePath() + " rename failed");
+ }
+ catch (Exception e)
+ {
+ InternalError ierr = new InternalError(file.getAbsolutePath());
+ ierr.initCause(e);
+ throw ierr;
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/AbstractMethodGenerator.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/AbstractMethodGenerator.java
new file mode 100644
index 000000000..7c6b7222f
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/AbstractMethodGenerator.java
@@ -0,0 +1,53 @@
+/* AbstractMethodGenerator.java -- the abstract method generator
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+public interface AbstractMethodGenerator
+{
+ /**
+ * Generate this method for the Stub (remote caller) class.
+ */
+ String generateStubMethod();
+
+ /**
+ * Generate this method for the Tie (remote servant) class.
+ */
+ String generateTieMethod();
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/ClassRmicCompiler.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/ClassRmicCompiler.java
new file mode 100644
index 000000000..9ac103c75
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/ClassRmicCompiler.java
@@ -0,0 +1,1834 @@
+/* ClassRmicCompiler.java --
+ Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmic;
+
+import gnu.java.rmi.server.RMIHashes;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.rmi.MarshalException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.UnexpectedException;
+import java.rmi.UnmarshalException;
+import java.rmi.server.Operation;
+import java.rmi.server.RemoteCall;
+import java.rmi.server.RemoteObject;
+import java.rmi.server.RemoteRef;
+import java.rmi.server.RemoteStub;
+import java.rmi.server.Skeleton;
+import java.rmi.server.SkeletonMismatchException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Type;
+
+public class ClassRmicCompiler
+ implements RmicBackend
+{
+ private String[] args;
+ private int next;
+ private List errors = new ArrayList();
+ private boolean keep = false;
+ private boolean need11Stubs = true;
+ private boolean need12Stubs = true;
+ private boolean compile = true;
+ private boolean verbose;
+ private boolean noWrite;
+ private String destination;
+ private String classpath;
+ private ClassLoader loader;
+ private int errorCount = 0;
+
+ private Class clazz;
+ private String classname;
+ private String classInternalName;
+ private String fullclassname;
+ private MethodRef[] remotemethods;
+ private String stubname;
+ private String skelname;
+ private List mRemoteInterfaces;
+
+ /**
+ * @return true if run was successful
+ */
+ public boolean run(String[] inputFiles)
+ {
+ args = inputFiles;
+
+ if (next >= args.length)
+ return false;
+
+ for (int i = next; i < args.length; i++)
+ {
+ try
+ {
+ if (verbose)
+ System.out.println("[Processing class " + args[i] + ".class]");
+ processClass(args[i].replace(File.separatorChar, '.'));
+ }
+ catch (IOException e)
+ {
+ errors.add(e);
+ }
+ catch (RMICException e)
+ {
+ errors.add(e);
+ }
+ }
+ if (errors.size() > 0)
+ {
+ for (Iterator it = errors.iterator(); it.hasNext(); )
+ {
+ Exception ex = (Exception) it.next();
+ logError(ex);
+ }
+ }
+
+ return errorCount == 0;
+ }
+
+ private void processClass(String cls) throws IOException, RMICException
+ {
+ // reset class specific vars
+ clazz = null;
+ classname = null;
+ classInternalName = null;
+ fullclassname = null;
+ remotemethods = null;
+ stubname = null;
+ skelname = null;
+ mRemoteInterfaces = new ArrayList();
+
+ analyzeClass(cls);
+ generateStub();
+ if (need11Stubs)
+ generateSkel();
+ }
+
+ private void analyzeClass(String cname)
+ throws RMICException
+ {
+ if (verbose)
+ System.out.println("[analyze class " + cname + "]");
+ int p = cname.lastIndexOf('.');
+ if (p != -1)
+ classname = cname.substring(p + 1);
+ else
+ classname = cname;
+ fullclassname = cname;
+
+ findClass();
+ findRemoteMethods();
+ }
+
+ /**
+ * @deprecated
+ */
+ public Exception getException()
+ {
+ return errors.size() == 0 ? null : (Exception) errors.get(0);
+ }
+
+ private void findClass()
+ throws RMICException
+ {
+ ClassLoader cl = (loader == null
+ ? ClassLoader.getSystemClassLoader()
+ : loader);
+ try
+ {
+ clazz = Class.forName(fullclassname, false, cl);
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ throw new RMICException
+ ("Class " + fullclassname + " not found in classpath", cnfe);
+ }
+
+ if (! Remote.class.isAssignableFrom(clazz))
+ {
+ throw new RMICException
+ ("Class " + clazz.getName()
+ + " does not implement a remote interface.");
+ }
+ }
+
+ private static Type[] typeArray(Class[] cls)
+ {
+ Type[] t = new Type[cls.length];
+ for (int i = 0; i < cls.length; i++)
+ {
+ t[i] = Type.getType(cls[i]);
+ }
+
+ return t;
+ }
+
+ private static String[] internalNameArray(Type[] t)
+ {
+ String[] s = new String[t.length];
+ for (int i = 0; i < t.length; i++)
+ {
+ s[i] = t[i].getInternalName();
+ }
+
+ return s;
+ }
+
+ private static String[] internalNameArray(Class[] c)
+ {
+ return internalNameArray(typeArray(c));
+ }
+
+ private static final String forName = "class$";
+
+ private static Object param(Method m, int argIndex)
+ {
+ List l = new ArrayList();
+ l.add(m);
+ l.add(new Integer(argIndex));
+ return l;
+ }
+
+ private static void generateClassForNamer(ClassVisitor cls)
+ {
+ MethodVisitor cv =
+ cls.visitMethod
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC, forName,
+ Type.getMethodDescriptor
+ (Type.getType(Class.class), new Type[] { Type.getType(String.class) }),
+ null, null);
+
+ Label start = new Label();
+ cv.visitLabel(start);
+ cv.visitVarInsn(Opcodes.ALOAD, 0);
+ cv.visitMethodInsn
+ (Opcodes.INVOKESTATIC,
+ Type.getInternalName(Class.class),
+ "forName",
+ Type.getMethodDescriptor
+ (Type.getType(Class.class), new Type[] { Type.getType(String.class) }));
+ cv.visitInsn(Opcodes.ARETURN);
+
+ Label handler = new Label();
+ cv.visitLabel(handler);
+ cv.visitVarInsn(Opcodes.ASTORE, 1);
+ cv.visitTypeInsn(Opcodes.NEW, typeArg(NoClassDefFoundError.class));
+ cv.visitInsn(Opcodes.DUP);
+ cv.visitVarInsn(Opcodes.ALOAD, 1);
+ cv.visitMethodInsn
+ (Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(ClassNotFoundException.class),
+ "getMessage",
+ Type.getMethodDescriptor(Type.getType(String.class), new Type[] {}));
+ cv.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(NoClassDefFoundError.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
+ cv.visitInsn(Opcodes.ATHROW);
+ cv.visitTryCatchBlock
+ (start, handler, handler,
+ Type.getInternalName(ClassNotFoundException.class));
+ cv.visitMaxs(-1, -1);
+ }
+
+ private void generateClassConstant(MethodVisitor cv, Class cls) {
+ if (cls.isPrimitive())
+ {
+ Class boxCls;
+ if (cls.equals(Boolean.TYPE))
+ boxCls = Boolean.class;
+ else if (cls.equals(Character.TYPE))
+ boxCls = Character.class;
+ else if (cls.equals(Byte.TYPE))
+ boxCls = Byte.class;
+ else if (cls.equals(Short.TYPE))
+ boxCls = Short.class;
+ else if (cls.equals(Integer.TYPE))
+ boxCls = Integer.class;
+ else if (cls.equals(Long.TYPE))
+ boxCls = Long.class;
+ else if (cls.equals(Float.TYPE))
+ boxCls = Float.class;
+ else if (cls.equals(Double.TYPE))
+ boxCls = Double.class;
+ else if (cls.equals(Void.TYPE))
+ boxCls = Void.class;
+ else
+ throw new IllegalArgumentException("unknown primitive type " + cls);
+
+ cv.visitFieldInsn
+ (Opcodes.GETSTATIC, Type.getInternalName(boxCls), "TYPE",
+ Type.getDescriptor(Class.class));
+ return;
+ }
+ cv.visitLdcInsn(cls.getName());
+ cv.visitMethodInsn
+ (Opcodes.INVOKESTATIC, classInternalName, forName,
+ Type.getMethodDescriptor
+ (Type.getType(Class.class),
+ new Type[] { Type.getType(String.class) }));
+ }
+
+ private void generateClassArray(MethodVisitor code, Class[] classes)
+ {
+ code.visitLdcInsn(new Integer(classes.length));
+ code.visitTypeInsn(Opcodes.ANEWARRAY, typeArg(Class.class));
+ for (int i = 0; i < classes.length; i++)
+ {
+ code.visitInsn(Opcodes.DUP);
+ code.visitLdcInsn(new Integer(i));
+ generateClassConstant(code, classes[i]);
+ code.visitInsn(Opcodes.AASTORE);
+ }
+ }
+
+ private void fillOperationArray(MethodVisitor clinit)
+ {
+ // Operations array
+ clinit.visitLdcInsn(new Integer(remotemethods.length));
+ clinit.visitTypeInsn(Opcodes.ANEWARRAY, typeArg(Operation.class));
+ clinit.visitFieldInsn
+ (Opcodes.PUTSTATIC, classInternalName, "operations",
+ Type.getDescriptor(Operation[].class));
+
+ for (int i = 0; i < remotemethods.length; i++)
+ {
+ Method m = remotemethods[i].meth;
+
+ StringBuilder desc = new StringBuilder();
+ desc.append(getPrettyName(m.getReturnType()) + " ");
+ desc.append(m.getName() + "(");
+
+ // signature
+ Class[] sig = m.getParameterTypes();
+ for (int j = 0; j < sig.length; j++)
+ {
+ desc.append(getPrettyName(sig[j]));
+ if (j + 1 < sig.length)
+ desc.append(", ");
+ }
+
+ // push operations array
+ clinit.visitFieldInsn
+ (Opcodes.GETSTATIC, classInternalName, "operations",
+ Type.getDescriptor(Operation[].class));
+
+ // push array index
+ clinit.visitLdcInsn(new Integer(i));
+
+ // instantiate operation and leave a copy on the stack
+ clinit.visitTypeInsn(Opcodes.NEW, typeArg(Operation.class));
+ clinit.visitInsn(Opcodes.DUP);
+ clinit.visitLdcInsn(desc.toString());
+ clinit.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(Operation.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
+
+ // store in operations array
+ clinit.visitInsn(Opcodes.AASTORE);
+ }
+ }
+
+ private void generateStaticMethodObjs(MethodVisitor clinit)
+ {
+ for (int i = 0; i < remotemethods.length; i++)
+ {
+ Method m = remotemethods[i].meth;
+
+ /*
+ * $method_<i>m.getName()</i>_<i>i</i> =
+ * <i>m.getDeclaringClass()</i>.class.getMethod
+ * (m.getName(), m.getParameterType())
+ */
+ String methodVar = "$method_" + m.getName() + "_" + i;
+ generateClassConstant(clinit, m.getDeclaringClass());
+ clinit.visitLdcInsn(m.getName());
+ generateClassArray(clinit, m.getParameterTypes());
+ clinit.visitMethodInsn
+ (Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(Class.class),
+ "getMethod",
+ Type.getMethodDescriptor
+ (Type.getType(Method.class),
+ new Type[] { Type.getType(String.class),
+ Type.getType(Class[].class) }));
+
+ clinit.visitFieldInsn
+ (Opcodes.PUTSTATIC, classInternalName, methodVar,
+ Type.getDescriptor(Method.class));
+ }
+ }
+
+ private void generateStub()
+ throws IOException
+ {
+ stubname = fullclassname + "_Stub";
+ String stubclassname = classname + "_Stub";
+ File file = new File((destination == null ? "." : destination)
+ + File.separator
+ + stubname.replace('.', File.separatorChar)
+ + ".class");
+
+ if (verbose)
+ System.out.println("[Generating class " + stubname + "]");
+
+ final ClassWriter stub = new ClassWriter(true);
+ classInternalName = stubname.replace('.', '/');
+ final String superInternalName =
+ Type.getType(RemoteStub.class).getInternalName();
+
+ String[] remoteInternalNames =
+ internalNameArray((Class[]) mRemoteInterfaces.toArray(new Class[] {}));
+ stub.visit
+ (Opcodes.V1_2, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, classInternalName,
+ null, superInternalName, remoteInternalNames);
+
+ if (need12Stubs)
+ {
+ stub.visitField
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "serialVersionUID",
+ Type.LONG_TYPE.getDescriptor(), null, new Long(2L));
+ }
+
+ if (need11Stubs)
+ {
+ stub.visitField
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL,
+ "interfaceHash", Type.LONG_TYPE.getDescriptor(), null,
+ new Long(RMIHashes.getInterfaceHash(clazz)));
+
+ if (need12Stubs)
+ {
+ stub.visitField
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, "useNewInvoke",
+ Type.BOOLEAN_TYPE.getDescriptor(), null, null);
+ }
+
+ stub.visitField
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL,
+ "operations", Type.getDescriptor(Operation[].class), null, null);
+ }
+
+ // Set of method references.
+ if (need12Stubs)
+ {
+ for (int i = 0; i < remotemethods.length; i++)
+ {
+ Method m = remotemethods[i].meth;
+ String slotName = "$method_" + m.getName() + "_" + i;
+ stub.visitField
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, slotName,
+ Type.getDescriptor(Method.class), null, null);
+ }
+ }
+
+ MethodVisitor clinit = stub.visitMethod
+ (Opcodes.ACC_STATIC, "<clinit>",
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
+
+ if (need11Stubs)
+ {
+ fillOperationArray(clinit);
+ if (! need12Stubs)
+ clinit.visitInsn(Opcodes.RETURN);
+ }
+
+ if (need12Stubs)
+ {
+ // begin of try
+ Label begin = new Label();
+
+ // beginning of catch
+ Label handler = new Label();
+ clinit.visitLabel(begin);
+
+ // Initialize the methods references.
+ if (need11Stubs)
+ {
+ /*
+ * RemoteRef.class.getMethod("invoke", new Class[] {
+ * Remote.class, Method.class, Object[].class, long.class })
+ */
+ generateClassConstant(clinit, RemoteRef.class);
+ clinit.visitLdcInsn("invoke");
+ generateClassArray
+ (clinit, new Class[] { Remote.class, Method.class,
+ Object[].class, long.class });
+ clinit.visitMethodInsn
+ (Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName(Class.class),
+ "getMethod",
+ Type.getMethodDescriptor
+ (Type.getType(Method.class),
+ new Type[] { Type.getType(String.class),
+ Type.getType(Class[].class) }));
+
+ // useNewInvoke = true
+ clinit.visitInsn(Opcodes.ICONST_1);
+ clinit.visitFieldInsn
+ (Opcodes.PUTSTATIC, classInternalName, "useNewInvoke",
+ Type.BOOLEAN_TYPE.getDescriptor());
+ }
+
+ generateStaticMethodObjs(clinit);
+
+ // jump past handler
+ clinit.visitInsn(Opcodes.RETURN);
+ clinit.visitLabel(handler);
+ if (need11Stubs)
+ {
+ // useNewInvoke = false
+ clinit.visitInsn(Opcodes.ICONST_0);
+ clinit.visitFieldInsn
+ (Opcodes.PUTSTATIC, classInternalName, "useNewInvoke",
+ Type.BOOLEAN_TYPE.getDescriptor());
+ clinit.visitInsn(Opcodes.RETURN);
+ }
+ else
+ {
+ // throw NoSuchMethodError
+ clinit.visitTypeInsn(Opcodes.NEW, typeArg(NoSuchMethodError.class));
+ clinit.visitInsn(Opcodes.DUP);
+ clinit.visitLdcInsn("stub class initialization failed");
+ clinit.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(NoSuchMethodError.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(String.class) }));
+ clinit.visitInsn(Opcodes.ATHROW);
+ }
+
+ clinit.visitTryCatchBlock
+ (begin, handler, handler,
+ Type.getInternalName(NoSuchMethodException.class));
+
+ }
+
+ clinit.visitMaxs(-1, -1);
+
+ generateClassForNamer(stub);
+
+ // Constructors
+ if (need11Stubs)
+ {
+ // no arg public constructor
+ MethodVisitor code = stub.visitMethod
+ (Opcodes.ACC_PUBLIC, "<init>",
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}),
+ null, null);
+ code.visitVarInsn(Opcodes.ALOAD, 0);
+ code.visitMethodInsn
+ (Opcodes.INVOKESPECIAL, superInternalName, "<init>",
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
+ code.visitInsn(Opcodes.RETURN);
+
+ code.visitMaxs(-1, -1);
+ }
+
+ // public RemoteRef constructor
+ MethodVisitor constructor = stub.visitMethod
+ (Opcodes.ACC_PUBLIC, "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)}),
+ null, null);
+ constructor.visitVarInsn(Opcodes.ALOAD, 0);
+ constructor.visitVarInsn(Opcodes.ALOAD, 1);
+ constructor.visitMethodInsn
+ (Opcodes.INVOKESPECIAL, superInternalName, "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)}));
+ constructor.visitInsn(Opcodes.RETURN);
+ constructor.visitMaxs(-1, -1);
+
+ // Method implementations
+ for (int i = 0; i < remotemethods.length; i++)
+ {
+ Method m = remotemethods[i].meth;
+ Class[] sig = m.getParameterTypes();
+ Class returntype = m.getReturnType();
+ Class[] except = sortExceptions
+ ((Class[]) remotemethods[i].exceptions.toArray(new Class[0]));
+
+ MethodVisitor code = stub.visitMethod
+ (Opcodes.ACC_PUBLIC,
+ m.getName(),
+ Type.getMethodDescriptor(Type.getType(returntype), typeArray(sig)),
+ null,
+ internalNameArray(typeArray(except)));
+
+ final Variables var = new Variables();
+
+ // this and parameters are the declared vars
+ var.declare("this");
+ for (int j = 0; j < sig.length; j++)
+ var.declare(param(m, j), size(sig[j]));
+
+ Label methodTryBegin = new Label();
+ code.visitLabel(methodTryBegin);
+
+ if (need12Stubs)
+ {
+ Label oldInvoke = new Label();
+ if (need11Stubs)
+ {
+ // if not useNewInvoke jump to old invoke
+ code.visitFieldInsn
+ (Opcodes.GETSTATIC, classInternalName, "useNewInvoke",
+ Type.getDescriptor(boolean.class));
+ code.visitJumpInsn(Opcodes.IFEQ, oldInvoke);
+ }
+
+ // this.ref
+ code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
+ code.visitFieldInsn
+ (Opcodes.GETFIELD, Type.getInternalName(RemoteObject.class),
+ "ref", Type.getDescriptor(RemoteRef.class));
+
+ // "this" is first arg to invoke
+ code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
+
+ // method object is second arg to invoke
+ String methName = "$method_" + m.getName() + "_" + i;
+ code.visitFieldInsn
+ (Opcodes.GETSTATIC, classInternalName, methName,
+ Type.getDescriptor(Method.class));
+
+ // args to remote method are third arg to invoke
+ if (sig.length == 0)
+ code.visitInsn(Opcodes.ACONST_NULL);
+ else
+ {
+ // create arg Object[] (with boxed primitives) and push it
+ code.visitLdcInsn(new Integer(sig.length));
+ code.visitTypeInsn(Opcodes.ANEWARRAY, typeArg(Object.class));
+
+ var.allocate("argArray");
+ code.visitVarInsn(Opcodes.ASTORE, var.get("argArray"));
+
+ for (int j = 0; j < sig.length; j++)
+ {
+ int size = size(sig[j]);
+ int insn = loadOpcode(sig[j]);
+ Class box = sig[j].isPrimitive() ? box(sig[j]) : null;
+
+ code.visitVarInsn(Opcodes.ALOAD, var.get("argArray"));
+ code.visitLdcInsn(new Integer(j));
+
+ // put argument on stack
+ if (box != null)
+ {
+ code.visitTypeInsn(Opcodes.NEW, typeArg(box));
+ code.visitInsn(Opcodes.DUP);
+ code.visitVarInsn(insn, var.get(param(m, j)));
+ code.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(box),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(sig[j]) }));
+ }
+ else
+ code.visitVarInsn(insn, var.get(param(m, j)));
+
+ code.visitInsn(Opcodes.AASTORE);
+ }
+
+ code.visitVarInsn(Opcodes.ALOAD, var.deallocate("argArray"));
+ }
+
+ // push remote operation opcode
+ code.visitLdcInsn(new Long(remotemethods[i].hash));
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteRef.class),
+ "invoke",
+ Type.getMethodDescriptor
+ (Type.getType(Object.class),
+ new Type[] { Type.getType(Remote.class),
+ Type.getType(Method.class),
+ Type.getType(Object[].class),
+ Type.LONG_TYPE }));
+
+ if (! returntype.equals(Void.TYPE))
+ {
+ int retcode = returnOpcode(returntype);
+ Class boxCls =
+ returntype.isPrimitive() ? box(returntype) : null;
+ code.visitTypeInsn
+ (Opcodes.CHECKCAST, typeArg(boxCls == null ? returntype : boxCls));
+ if (returntype.isPrimitive())
+ {
+ // unbox
+ code.visitMethodInsn
+ (Opcodes.INVOKEVIRTUAL,
+ Type.getType(boxCls).getInternalName(),
+ unboxMethod(returntype),
+ Type.getMethodDescriptor
+ (Type.getType(returntype), new Type[] {}));
+ }
+
+ code.visitInsn(retcode);
+ }
+ else
+ code.visitInsn(Opcodes.RETURN);
+
+
+ if (need11Stubs)
+ code.visitLabel(oldInvoke);
+ }
+
+ if (need11Stubs)
+ {
+
+ // this.ref.newCall(this, operations, index, interfaceHash)
+ code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
+ code.visitFieldInsn
+ (Opcodes.GETFIELD,
+ Type.getInternalName(RemoteObject.class),
+ "ref",
+ Type.getDescriptor(RemoteRef.class));
+
+ // "this" is first arg to newCall
+ code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
+
+ // operations is second arg to newCall
+ code.visitFieldInsn
+ (Opcodes.GETSTATIC, classInternalName, "operations",
+ Type.getDescriptor(Operation[].class));
+
+ // method index is third arg
+ code.visitLdcInsn(new Integer(i));
+
+ // interface hash is fourth arg
+ code.visitFieldInsn
+ (Opcodes.GETSTATIC, classInternalName, "interfaceHash",
+ Type.LONG_TYPE.getDescriptor());
+
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteRef.class),
+ "newCall",
+ Type.getMethodDescriptor
+ (Type.getType(RemoteCall.class),
+ new Type[] { Type.getType(RemoteObject.class),
+ Type.getType(Operation[].class),
+ Type.INT_TYPE,
+ Type.LONG_TYPE }));
+
+ // store call object on stack and leave copy on stack
+ var.allocate("call");
+ code.visitInsn(Opcodes.DUP);
+ code.visitVarInsn(Opcodes.ASTORE, var.get("call"));
+
+ Label beginArgumentTryBlock = new Label();
+ code.visitLabel(beginArgumentTryBlock);
+
+ // ObjectOutput out = call.getOutputStream();
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteCall.class),
+ "getOutputStream",
+ Type.getMethodDescriptor
+ (Type.getType(ObjectOutput.class), new Type[] {}));
+
+ for (int j = 0; j < sig.length; j++)
+ {
+ // dup the ObjectOutput
+ code.visitInsn(Opcodes.DUP);
+
+ // get j'th arg to remote method
+ code.visitVarInsn(loadOpcode(sig[j]), var.get(param(m, j)));
+
+ Class argCls =
+ sig[j].isPrimitive() ? sig[j] : Object.class;
+
+ // out.writeFoo
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(ObjectOutput.class),
+ writeMethod(sig[j]),
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(argCls) }));
+ }
+
+ // pop ObjectOutput
+ code.visitInsn(Opcodes.POP);
+
+ Label iohandler = new Label();
+ Label endArgumentTryBlock = new Label();
+ code.visitJumpInsn(Opcodes.GOTO, endArgumentTryBlock);
+ code.visitLabel(iohandler);
+
+ // throw new MarshalException(msg, ioexception);
+ code.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
+ code.visitTypeInsn(Opcodes.NEW, typeArg(MarshalException.class));
+ code.visitInsn(Opcodes.DUP);
+ code.visitLdcInsn("error marshalling arguments");
+ code.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
+ code.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(MarshalException.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(String.class),
+ Type.getType(Exception.class) }));
+ code.visitInsn(Opcodes.ATHROW);
+
+ code.visitLabel(endArgumentTryBlock);
+ code.visitTryCatchBlock
+ (beginArgumentTryBlock, iohandler, iohandler,
+ Type.getInternalName(IOException.class));
+
+ // this.ref.invoke(call)
+ code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
+ code.visitFieldInsn
+ (Opcodes.GETFIELD, Type.getInternalName(RemoteObject.class),
+ "ref", Type.getDescriptor(RemoteRef.class));
+ code.visitVarInsn(Opcodes.ALOAD, var.get("call"));
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteRef.class),
+ "invoke",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(RemoteCall.class) }));
+
+ // handle return value
+ boolean needcastcheck = false;
+
+ Label beginReturnTryCatch = new Label();
+ code.visitLabel(beginReturnTryCatch);
+
+ int returncode = returnOpcode(returntype);
+
+ if (! returntype.equals(Void.TYPE))
+ {
+ // call.getInputStream()
+ code.visitVarInsn(Opcodes.ALOAD, var.get("call"));
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteCall.class),
+ "getInputStream",
+ Type.getMethodDescriptor
+ (Type.getType(ObjectInput.class), new Type[] {}));
+
+ Class readCls =
+ returntype.isPrimitive() ? returntype : Object.class;
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(ObjectInput.class),
+ readMethod(returntype),
+ Type.getMethodDescriptor
+ (Type.getType(readCls), new Type[] {}));
+
+ boolean castresult = false;
+
+ if (! returntype.isPrimitive())
+ {
+ if (! returntype.equals(Object.class))
+ castresult = true;
+ else
+ needcastcheck = true;
+ }
+
+ if (castresult)
+ code.visitTypeInsn(Opcodes.CHECKCAST, typeArg(returntype));
+
+ // leave result on stack for return
+ }
+
+ // this.ref.done(call)
+ code.visitVarInsn(Opcodes.ALOAD, var.get("this"));
+ code.visitFieldInsn
+ (Opcodes.GETFIELD,
+ Type.getInternalName(RemoteObject.class),
+ "ref",
+ Type.getDescriptor(RemoteRef.class));
+ code.visitVarInsn(Opcodes.ALOAD, var.deallocate("call"));
+ code.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteRef.class),
+ "done",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(RemoteCall.class) }));
+
+ // return; or return result;
+ code.visitInsn(returncode);
+
+ // exception handler
+ Label handler = new Label();
+ code.visitLabel(handler);
+ code.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
+
+ // throw new UnmarshalException(msg, e)
+ code.visitTypeInsn(Opcodes.NEW, typeArg(UnmarshalException.class));
+ code.visitInsn(Opcodes.DUP);
+ code.visitLdcInsn("error unmarshalling return");
+ code.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
+ code.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(UnmarshalException.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(String.class),
+ Type.getType(Exception.class) }));
+ code.visitInsn(Opcodes.ATHROW);
+
+ Label endReturnTryCatch = new Label();
+
+ // catch IOException
+ code.visitTryCatchBlock
+ (beginReturnTryCatch, handler, handler,
+ Type.getInternalName(IOException.class));
+
+ if (needcastcheck)
+ {
+ // catch ClassNotFoundException
+ code.visitTryCatchBlock
+ (beginReturnTryCatch, handler, handler,
+ Type.getInternalName(ClassNotFoundException.class));
+ }
+ }
+
+ Label rethrowHandler = new Label();
+ code.visitLabel(rethrowHandler);
+ // rethrow declared exceptions
+ code.visitInsn(Opcodes.ATHROW);
+
+ boolean needgeneral = true;
+ for (int j = 0; j < except.length; j++)
+ {
+ if (except[j] == Exception.class)
+ needgeneral = false;
+ }
+
+ for (int j = 0; j < except.length; j++)
+ {
+ code.visitTryCatchBlock
+ (methodTryBegin, rethrowHandler, rethrowHandler,
+ Type.getInternalName(except[j]));
+ }
+
+ if (needgeneral)
+ {
+ // rethrow unchecked exceptions
+ code.visitTryCatchBlock
+ (methodTryBegin, rethrowHandler, rethrowHandler,
+ Type.getInternalName(RuntimeException.class));
+
+ Label generalHandler = new Label();
+ code.visitLabel(generalHandler);
+ String msg = "undeclared checked exception";
+
+ // throw new java.rmi.UnexpectedException(msg, e)
+ code.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
+ code.visitTypeInsn(Opcodes.NEW, typeArg(UnexpectedException.class));
+ code.visitInsn(Opcodes.DUP);
+ code.visitLdcInsn(msg);
+ code.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
+ code.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(UnexpectedException.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type [] { Type.getType(String.class),
+ Type.getType(Exception.class) }));
+ code.visitInsn(Opcodes.ATHROW);
+
+ code.visitTryCatchBlock
+ (methodTryBegin, rethrowHandler, generalHandler,
+ Type.getInternalName(Exception.class));
+ }
+
+ code.visitMaxs(-1, -1);
+ }
+
+ stub.visitEnd();
+ byte[] classData = stub.toByteArray();
+ if (!noWrite)
+ {
+ if (file.exists())
+ file.delete();
+ if (file.getParentFile() != null)
+ file.getParentFile().mkdirs();
+ FileOutputStream fos = new FileOutputStream(file);
+ fos.write(classData);
+ fos.flush();
+ fos.close();
+ }
+ }
+
+ private void generateSkel() throws IOException
+ {
+ skelname = fullclassname + "_Skel";
+ String skelclassname = classname + "_Skel";
+ File file = new File(destination == null ? "" : destination
+ + File.separator
+ + skelname.replace('.', File.separatorChar)
+ + ".class");
+ if (verbose)
+ System.out.println("[Generating class " + skelname + "]");
+
+ final ClassWriter skel = new ClassWriter(true);
+ classInternalName = skelname.replace('.', '/');
+ skel.visit
+ (Opcodes.V1_1, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL,
+ classInternalName, Type.getInternalName(Object.class), null,
+ new String[] { Type.getType(Skeleton.class).getInternalName() });
+
+ skel.visitField
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "interfaceHash",
+ Type.LONG_TYPE.getDescriptor(), null,
+ new Long(RMIHashes.getInterfaceHash(clazz)));
+
+ skel.visitField
+ (Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "operations",
+ Type.getDescriptor(Operation[].class), null, null);
+
+ MethodVisitor clinit = skel.visitMethod
+ (Opcodes.ACC_STATIC, "<clinit>",
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
+
+ fillOperationArray(clinit);
+ clinit.visitInsn(Opcodes.RETURN);
+
+ clinit.visitMaxs(-1, -1);
+
+ // no arg public constructor
+ MethodVisitor init = skel.visitMethod
+ (Opcodes.ACC_PUBLIC, "<init>",
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null);
+ init.visitVarInsn(Opcodes.ALOAD, 0);
+ init.visitMethodInsn
+ (Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>",
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
+ init.visitInsn(Opcodes.RETURN);
+ init.visitMaxs(-1, -1);
+
+ /*
+ * public Operation[] getOperations()
+ * returns a clone of the operations array
+ */
+ MethodVisitor getOp = skel.visitMethod
+ (Opcodes.ACC_PUBLIC, "getOperations",
+ Type.getMethodDescriptor
+ (Type.getType(Operation[].class), new Type[] {}),
+ null, null);
+ getOp.visitFieldInsn
+ (Opcodes.GETSTATIC, classInternalName, "operations",
+ Type.getDescriptor(Operation[].class));
+ getOp.visitMethodInsn
+ (Opcodes.INVOKEVIRTUAL, Type.getInternalName(Object.class),
+ "clone", Type.getMethodDescriptor(Type.getType(Object.class),
+ new Type[] {}));
+ getOp.visitTypeInsn(Opcodes.CHECKCAST, typeArg(Operation[].class));
+ getOp.visitInsn(Opcodes.ARETURN);
+ getOp.visitMaxs(-1, -1);
+
+ // public void dispatch(Remote, RemoteCall, int opnum, long hash)
+ MethodVisitor dispatch = skel.visitMethod
+ (Opcodes.ACC_PUBLIC,
+ "dispatch",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE,
+ new Type[] { Type.getType(Remote.class),
+ Type.getType(RemoteCall.class),
+ Type.INT_TYPE, Type.LONG_TYPE }), null,
+ new String[] { Type.getInternalName(Exception.class) });
+
+ Variables var = new Variables();
+ var.declare("this");
+ var.declare("remoteobj");
+ var.declare("remotecall");
+ var.declare("opnum");
+ var.declareWide("hash");
+
+ /*
+ * if opnum >= 0
+ * XXX it is unclear why there is handling of negative opnums
+ */
+ dispatch.visitVarInsn(Opcodes.ILOAD, var.get("opnum"));
+ Label nonNegativeOpnum = new Label();
+ Label opnumSet = new Label();
+ dispatch.visitJumpInsn(Opcodes.IFGE, nonNegativeOpnum);
+
+ for (int i = 0; i < remotemethods.length; i++)
+ {
+ // assign opnum if hash matches supplied hash
+ dispatch.visitVarInsn(Opcodes.LLOAD, var.get("hash"));
+ dispatch.visitLdcInsn(new Long(remotemethods[i].hash));
+ Label notIt = new Label();
+ dispatch.visitInsn(Opcodes.LCMP);
+ dispatch.visitJumpInsn(Opcodes.IFNE, notIt);
+
+ // opnum = <opnum>
+ dispatch.visitLdcInsn(new Integer(i));
+ dispatch.visitVarInsn(Opcodes.ISTORE, var.get("opnum"));
+ dispatch.visitJumpInsn(Opcodes.GOTO, opnumSet);
+ dispatch.visitLabel(notIt);
+ }
+
+ // throw new SkeletonMismatchException
+ Label mismatch = new Label();
+ dispatch.visitJumpInsn(Opcodes.GOTO, mismatch);
+
+ dispatch.visitLabel(nonNegativeOpnum);
+
+ // if opnum is already set, check that the hash matches the interface
+ dispatch.visitVarInsn(Opcodes.LLOAD, var.get("hash"));
+ dispatch.visitFieldInsn
+ (Opcodes.GETSTATIC, classInternalName,
+ "interfaceHash", Type.LONG_TYPE.getDescriptor());
+ dispatch.visitInsn(Opcodes.LCMP);
+ dispatch.visitJumpInsn(Opcodes.IFEQ, opnumSet);
+
+ dispatch.visitLabel(mismatch);
+ dispatch.visitTypeInsn
+ (Opcodes.NEW, typeArg(SkeletonMismatchException.class));
+ dispatch.visitInsn(Opcodes.DUP);
+ dispatch.visitLdcInsn("interface hash mismatch");
+ dispatch.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(SkeletonMismatchException.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
+ dispatch.visitInsn(Opcodes.ATHROW);
+
+ // opnum has been set
+ dispatch.visitLabel(opnumSet);
+
+ dispatch.visitVarInsn(Opcodes.ALOAD, var.get("remoteobj"));
+ dispatch.visitTypeInsn(Opcodes.CHECKCAST, typeArg(clazz));
+ dispatch.visitVarInsn(Opcodes.ASTORE, var.get("remoteobj"));
+
+ Label deflt = new Label();
+ Label[] methLabels = new Label[remotemethods.length];
+ for (int i = 0; i < methLabels.length; i++)
+ methLabels[i] = new Label();
+
+ // switch on opnum
+ dispatch.visitVarInsn(Opcodes.ILOAD, var.get("opnum"));
+ dispatch.visitTableSwitchInsn
+ (0, remotemethods.length - 1, deflt, methLabels);
+
+ // Method dispatch
+ for (int i = 0; i < remotemethods.length; i++)
+ {
+ dispatch.visitLabel(methLabels[i]);
+ Method m = remotemethods[i].meth;
+ generateMethodSkel(dispatch, m, var);
+ }
+
+ dispatch.visitLabel(deflt);
+ dispatch.visitTypeInsn(Opcodes.NEW, typeArg(UnmarshalException.class));
+ dispatch.visitInsn(Opcodes.DUP);
+ dispatch.visitLdcInsn("invalid method number");
+ dispatch.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(UnmarshalException.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] { Type.getType(String.class) }));
+ dispatch.visitInsn(Opcodes.ATHROW);
+
+ dispatch.visitMaxs(-1, -1);
+
+ skel.visitEnd();
+ byte[] classData = skel.toByteArray();
+ if (!noWrite)
+ {
+ if (file.exists())
+ file.delete();
+ if (file.getParentFile() != null)
+ file.getParentFile().mkdirs();
+ FileOutputStream fos = new FileOutputStream(file);
+ fos.write(classData);
+ fos.flush();
+ fos.close();
+ }
+ }
+
+ private void generateMethodSkel(MethodVisitor cv, Method m, Variables var)
+ {
+ Class[] sig = m.getParameterTypes();
+
+ Label readArgs = new Label();
+ cv.visitLabel(readArgs);
+
+ boolean needcastcheck = false;
+
+ // ObjectInput in = call.getInputStream();
+ cv.visitVarInsn(Opcodes.ALOAD, var.get("remotecall"));
+ cv.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteCall.class), "getInputStream",
+ Type.getMethodDescriptor
+ (Type.getType(ObjectInput.class), new Type[] {}));
+ cv.visitVarInsn(Opcodes.ASTORE, var.allocate("objectinput"));
+
+ for (int i = 0; i < sig.length; i++)
+ {
+ // dup input stream
+ cv.visitVarInsn(Opcodes.ALOAD, var.get("objectinput"));
+
+ Class readCls = sig[i].isPrimitive() ? sig[i] : Object.class;
+
+ // in.readFoo()
+ cv.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(ObjectInput.class),
+ readMethod(sig[i]),
+ Type.getMethodDescriptor
+ (Type.getType(readCls), new Type [] {}));
+
+ if (! sig[i].isPrimitive() && ! sig[i].equals(Object.class))
+ {
+ needcastcheck = true;
+ cv.visitTypeInsn(Opcodes.CHECKCAST, typeArg(sig[i]));
+ }
+
+ // store arg in variable
+ cv.visitVarInsn
+ (storeOpcode(sig[i]), var.allocate(param(m, i), size(sig[i])));
+ }
+
+ var.deallocate("objectinput");
+
+ Label doCall = new Label();
+ Label closeInput = new Label();
+
+ cv.visitJumpInsn(Opcodes.JSR, closeInput);
+ cv.visitJumpInsn(Opcodes.GOTO, doCall);
+
+ // throw new UnmarshalException
+ Label handler = new Label();
+ cv.visitLabel(handler);
+ cv.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
+ cv.visitTypeInsn(Opcodes.NEW, typeArg(UnmarshalException.class));
+ cv.visitInsn(Opcodes.DUP);
+ cv.visitLdcInsn("error unmarshalling arguments");
+ cv.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
+ cv.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(UnmarshalException.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] { Type.getType(String.class),
+ Type.getType(Exception.class) }));
+ cv.visitVarInsn(Opcodes.ASTORE, var.allocate("toThrow"));
+ cv.visitJumpInsn(Opcodes.JSR, closeInput);
+ cv.visitVarInsn(Opcodes.ALOAD, var.get("toThrow"));
+ cv.visitInsn(Opcodes.ATHROW);
+
+ cv.visitTryCatchBlock
+ (readArgs, handler, handler, Type.getInternalName(IOException.class));
+ if (needcastcheck)
+ {
+ cv.visitTryCatchBlock
+ (readArgs, handler, handler,
+ Type.getInternalName(ClassCastException.class));
+ }
+
+ // finally block
+ cv.visitLabel(closeInput);
+ cv.visitVarInsn(Opcodes.ASTORE, var.allocate("retAddress"));
+ cv.visitVarInsn(Opcodes.ALOAD, var.get("remotecall"));
+ cv.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteCall.class),
+ "releaseInputStream",
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));
+ cv.visitVarInsn(Opcodes.RET, var.deallocate("retAddress"));
+ var.deallocate("toThrow");
+
+ // do the call using args stored as variables
+ cv.visitLabel(doCall);
+ cv.visitVarInsn(Opcodes.ALOAD, var.get("remoteobj"));
+ for (int i = 0; i < sig.length; i++)
+ cv.visitVarInsn(loadOpcode(sig[i]), var.deallocate(param(m, i)));
+ cv.visitMethodInsn
+ (Opcodes.INVOKEVIRTUAL, Type.getInternalName(clazz), m.getName(),
+ Type.getMethodDescriptor(m));
+
+ Class returntype = m.getReturnType();
+ if (! returntype.equals(Void.TYPE))
+ {
+ cv.visitVarInsn
+ (storeOpcode(returntype), var.allocate("result", size(returntype)));
+ }
+
+ // write result to result stream
+ Label writeResult = new Label();
+ cv.visitLabel(writeResult);
+ cv.visitVarInsn(Opcodes.ALOAD, var.get("remotecall"));
+ cv.visitInsn(Opcodes.ICONST_1);
+ cv.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(RemoteCall.class),
+ "getResultStream",
+ Type.getMethodDescriptor
+ (Type.getType(ObjectOutput.class),
+ new Type[] { Type.BOOLEAN_TYPE }));
+
+ if (! returntype.equals(Void.TYPE))
+ {
+ // out.writeFoo(result)
+ cv.visitVarInsn(loadOpcode(returntype), var.deallocate("result"));
+ Class writeCls = returntype.isPrimitive() ? returntype : Object.class;
+ cv.visitMethodInsn
+ (Opcodes.INVOKEINTERFACE,
+ Type.getInternalName(ObjectOutput.class),
+ writeMethod(returntype),
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] { Type.getType(writeCls) }));
+ }
+
+ cv.visitInsn(Opcodes.RETURN);
+
+ // throw new MarshalException
+ Label marshalHandler = new Label();
+ cv.visitLabel(marshalHandler);
+ cv.visitVarInsn(Opcodes.ASTORE, var.allocate("exception"));
+ cv.visitTypeInsn(Opcodes.NEW, typeArg(MarshalException.class));
+ cv.visitInsn(Opcodes.DUP);
+ cv.visitLdcInsn("error marshalling return");
+ cv.visitVarInsn(Opcodes.ALOAD, var.deallocate("exception"));
+ cv.visitMethodInsn
+ (Opcodes.INVOKESPECIAL,
+ Type.getInternalName(MarshalException.class),
+ "<init>",
+ Type.getMethodDescriptor
+ (Type.VOID_TYPE, new Type[] { Type.getType(String.class),
+ Type.getType(Exception.class) }));
+ cv.visitInsn(Opcodes.ATHROW);
+ cv.visitTryCatchBlock
+ (writeResult, marshalHandler, marshalHandler,
+ Type.getInternalName(IOException.class));
+ }
+
+ private static String typeArg(Class cls)
+ {
+ if (cls.isArray())
+ return Type.getDescriptor(cls);
+
+ return Type.getInternalName(cls);
+ }
+
+ private static String readMethod(Class cls)
+ {
+ if (cls.equals(Void.TYPE))
+ throw new IllegalArgumentException("can not read void");
+
+ String method;
+ if (cls.equals(Boolean.TYPE))
+ method = "readBoolean";
+ else if (cls.equals(Byte.TYPE))
+ method = "readByte";
+ else if (cls.equals(Character.TYPE))
+ method = "readChar";
+ else if (cls.equals(Short.TYPE))
+ method = "readShort";
+ else if (cls.equals(Integer.TYPE))
+ method = "readInt";
+ else if (cls.equals(Long.TYPE))
+ method = "readLong";
+ else if (cls.equals(Float.TYPE))
+ method = "readFloat";
+ else if (cls.equals(Double.TYPE))
+ method = "readDouble";
+ else
+ method = "readObject";
+
+ return method;
+ }
+
+ private static String writeMethod(Class cls)
+ {
+ if (cls.equals(Void.TYPE))
+ throw new IllegalArgumentException("can not read void");
+
+ String method;
+ if (cls.equals(Boolean.TYPE))
+ method = "writeBoolean";
+ else if (cls.equals(Byte.TYPE))
+ method = "writeByte";
+ else if (cls.equals(Character.TYPE))
+ method = "writeChar";
+ else if (cls.equals(Short.TYPE))
+ method = "writeShort";
+ else if (cls.equals(Integer.TYPE))
+ method = "writeInt";
+ else if (cls.equals(Long.TYPE))
+ method = "writeLong";
+ else if (cls.equals(Float.TYPE))
+ method = "writeFloat";
+ else if (cls.equals(Double.TYPE))
+ method = "writeDouble";
+ else
+ method = "writeObject";
+
+ return method;
+ }
+
+ private static int returnOpcode(Class cls)
+ {
+ int returncode;
+ if (cls.equals(Boolean.TYPE))
+ returncode = Opcodes.IRETURN;
+ else if (cls.equals(Byte.TYPE))
+ returncode = Opcodes.IRETURN;
+ else if (cls.equals(Character.TYPE))
+ returncode = Opcodes.IRETURN;
+ else if (cls.equals(Short.TYPE))
+ returncode = Opcodes.IRETURN;
+ else if (cls.equals(Integer.TYPE))
+ returncode = Opcodes.IRETURN;
+ else if (cls.equals(Long.TYPE))
+ returncode = Opcodes.LRETURN;
+ else if (cls.equals(Float.TYPE))
+ returncode = Opcodes.FRETURN;
+ else if (cls.equals(Double.TYPE))
+ returncode = Opcodes.DRETURN;
+ else if (cls.equals(Void.TYPE))
+ returncode = Opcodes.RETURN;
+ else
+ returncode = Opcodes.ARETURN;
+
+ return returncode;
+ }
+
+ private static int loadOpcode(Class cls)
+ {
+ if (cls.equals(Void.TYPE))
+ throw new IllegalArgumentException("can not load void");
+
+ int loadcode;
+ if (cls.equals(Boolean.TYPE))
+ loadcode = Opcodes.ILOAD;
+ else if (cls.equals(Byte.TYPE))
+ loadcode = Opcodes.ILOAD;
+ else if (cls.equals(Character.TYPE))
+ loadcode = Opcodes.ILOAD;
+ else if (cls.equals(Short.TYPE))
+ loadcode = Opcodes.ILOAD;
+ else if (cls.equals(Integer.TYPE))
+ loadcode = Opcodes.ILOAD;
+ else if (cls.equals(Long.TYPE))
+ loadcode = Opcodes.LLOAD;
+ else if (cls.equals(Float.TYPE))
+ loadcode = Opcodes.FLOAD;
+ else if (cls.equals(Double.TYPE))
+ loadcode = Opcodes.DLOAD;
+ else
+ loadcode = Opcodes.ALOAD;
+
+ return loadcode;
+ }
+
+ private static int storeOpcode(Class cls)
+ {
+ if (cls.equals(Void.TYPE))
+ throw new IllegalArgumentException("can not load void");
+
+ int storecode;
+ if (cls.equals(Boolean.TYPE))
+ storecode = Opcodes.ISTORE;
+ else if (cls.equals(Byte.TYPE))
+ storecode = Opcodes.ISTORE;
+ else if (cls.equals(Character.TYPE))
+ storecode = Opcodes.ISTORE;
+ else if (cls.equals(Short.TYPE))
+ storecode = Opcodes.ISTORE;
+ else if (cls.equals(Integer.TYPE))
+ storecode = Opcodes.ISTORE;
+ else if (cls.equals(Long.TYPE))
+ storecode = Opcodes.LSTORE;
+ else if (cls.equals(Float.TYPE))
+ storecode = Opcodes.FSTORE;
+ else if (cls.equals(Double.TYPE))
+ storecode = Opcodes.DSTORE;
+ else
+ storecode = Opcodes.ASTORE;
+
+ return storecode;
+ }
+
+ private static String unboxMethod(Class primitive)
+ {
+ if (! primitive.isPrimitive())
+ throw new IllegalArgumentException("can not unbox nonprimitive");
+
+ String method;
+ if (primitive.equals(Boolean.TYPE))
+ method = "booleanValue";
+ else if (primitive.equals(Byte.TYPE))
+ method = "byteValue";
+ else if (primitive.equals(Character.TYPE))
+ method = "charValue";
+ else if (primitive.equals(Short.TYPE))
+ method = "shortValue";
+ else if (primitive.equals(Integer.TYPE))
+ method = "intValue";
+ else if (primitive.equals(Long.TYPE))
+ method = "longValue";
+ else if (primitive.equals(Float.TYPE))
+ method = "floatValue";
+ else if (primitive.equals(Double.TYPE))
+ method = "doubleValue";
+ else
+ throw new IllegalStateException("unknown primitive class " + primitive);
+
+ return method;
+ }
+
+ public static Class box(Class cls)
+ {
+ if (! cls.isPrimitive())
+ throw new IllegalArgumentException("can only box primitive");
+
+ Class box;
+ if (cls.equals(Boolean.TYPE))
+ box = Boolean.class;
+ else if (cls.equals(Byte.TYPE))
+ box = Byte.class;
+ else if (cls.equals(Character.TYPE))
+ box = Character.class;
+ else if (cls.equals(Short.TYPE))
+ box = Short.class;
+ else if (cls.equals(Integer.TYPE))
+ box = Integer.class;
+ else if (cls.equals(Long.TYPE))
+ box = Long.class;
+ else if (cls.equals(Float.TYPE))
+ box = Float.class;
+ else if (cls.equals(Double.TYPE))
+ box = Double.class;
+ else
+ throw new IllegalStateException("unknown primitive type " + cls);
+
+ return box;
+ }
+
+ private static int size(Class cls) {
+ if (cls.equals(Long.TYPE) || cls.equals(Double.TYPE))
+ return 2;
+ else
+ return 1;
+ }
+
+ /**
+ * Sort exceptions so the most general go last.
+ */
+ private Class[] sortExceptions(Class[] except)
+ {
+ for (int i = 0; i < except.length; i++)
+ {
+ for (int j = i + 1; j < except.length; j++)
+ {
+ if (except[i].isAssignableFrom(except[j]))
+ {
+ Class tmp = except[i];
+ except[i] = except[j];
+ except[j] = tmp;
+ }
+ }
+ }
+ return (except);
+ }
+
+ public void setup(boolean keep, boolean need11Stubs, boolean need12Stubs,
+ boolean iiop, boolean poa, boolean debug, boolean warnings,
+ boolean noWrite, boolean verbose, boolean force, String classpath,
+ String bootclasspath, String extdirs, String outputDirectory)
+ {
+ this.keep = keep;
+ this.need11Stubs = need11Stubs;
+ this.need12Stubs = need12Stubs;
+ this.verbose = verbose;
+ this.noWrite = noWrite;
+
+ // Set up classpath.
+ this.classpath = classpath;
+ StringTokenizer st =
+ new StringTokenizer(classpath, File.pathSeparator);
+ URL[] u = new URL[st.countTokens()];
+ for (int i = 0; i < u.length; i++)
+ {
+ String path = st.nextToken();
+ File f = new File(path);
+ try
+ {
+ u[i] = f.toURL();
+ }
+ catch (java.net.MalformedURLException mue)
+ {
+ logError("malformed classpath component " + path);
+ return;
+ }
+ }
+ loader = new URLClassLoader(u);
+
+ destination = outputDirectory;
+ }
+
+ private void findRemoteMethods()
+ throws RMICException
+ {
+ List rmeths = new ArrayList();
+ for (Class cur = clazz; cur != null; cur = cur.getSuperclass())
+ {
+ Class[] interfaces = cur.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ if (java.rmi.Remote.class.isAssignableFrom(interfaces[i]))
+ {
+ Class remoteInterface = interfaces[i];
+ if (verbose)
+ System.out.println
+ ("[implements " + remoteInterface.getName() + "]");
+
+ // check if the methods declare RemoteExceptions
+ Method[] meths = remoteInterface.getMethods();
+ for (int j = 0; j < meths.length; j++)
+ {
+ Method m = meths[j];
+ Class[] exs = m.getExceptionTypes();
+
+ boolean throwsRemote = false;
+ for (int k = 0; k < exs.length; k++)
+ {
+ if (exs[k].isAssignableFrom(RemoteException.class))
+ throwsRemote = true;
+ }
+
+ if (! throwsRemote)
+ {
+ throw new RMICException
+ ("Method " + m + " in interface " + remoteInterface
+ + " does not throw a RemoteException");
+ }
+
+ rmeths.add(m);
+ }
+
+ mRemoteInterfaces.add(remoteInterface);
+ }
+ }
+ }
+
+ // intersect exceptions for doubly inherited methods
+ boolean[] skip = new boolean[rmeths.size()];
+ for (int i = 0; i < skip.length; i++)
+ skip[i] = false;
+ List methrefs = new ArrayList();
+ for (int i = 0; i < rmeths.size(); i++)
+ {
+ if (skip[i]) continue;
+ Method current = (Method) rmeths.get(i);
+ MethodRef ref = new MethodRef(current);
+ for (int j = i+1; j < rmeths.size(); j++)
+ {
+ Method other = (Method) rmeths.get(j);
+ if (ref.isMatch(other))
+ {
+ ref.intersectExceptions(other);
+ skip[j] = true;
+ }
+ }
+ methrefs.add(ref);
+ }
+
+ // Convert into a MethodRef array and sort them
+ remotemethods = (MethodRef[])
+ methrefs.toArray(new MethodRef[methrefs.size()]);
+ Arrays.sort(remotemethods);
+ }
+
+ /**
+ * Prints an error to System.err and increases the error count.
+ */
+ private void logError(Exception theError)
+ {
+ logError(theError.getMessage());
+ if (verbose)
+ theError.printStackTrace(System.err);
+ }
+
+ /**
+ * Prints an error to System.err and increases the error count.
+ */
+ private void logError(String theError)
+ {
+ errorCount++;
+ System.err.println("error: " + theError);
+ }
+
+ private static String getPrettyName(Class cls)
+ {
+ StringBuilder str = new StringBuilder();
+ for (int count = 0;; count++)
+ {
+ if (! cls.isArray())
+ {
+ str.append(cls.getName());
+ for (; count > 0; count--)
+ str.append("[]");
+ return (str.toString());
+ }
+ cls = cls.getComponentType();
+ }
+ }
+
+ private static class MethodRef
+ implements Comparable
+ {
+ Method meth;
+ long hash;
+ List exceptions;
+ private String sig;
+
+ MethodRef(Method m) {
+ meth = m;
+ sig = Type.getMethodDescriptor(meth);
+ hash = RMIHashes.getMethodHash(m);
+ // add exceptions removing subclasses
+ exceptions = removeSubclasses(m.getExceptionTypes());
+ }
+
+ public int compareTo(Object obj) {
+ MethodRef that = (MethodRef) obj;
+ int name = this.meth.getName().compareTo(that.meth.getName());
+ if (name == 0) {
+ return this.sig.compareTo(that.sig);
+ }
+ return name;
+ }
+
+ public boolean isMatch(Method m)
+ {
+ if (!meth.getName().equals(m.getName()))
+ return false;
+
+ Class[] params1 = meth.getParameterTypes();
+ Class[] params2 = m.getParameterTypes();
+ if (params1.length != params2.length)
+ return false;
+
+ for (int i = 0; i < params1.length; i++)
+ if (!params1[i].equals(params2[i])) return false;
+
+ return true;
+ }
+
+ private static List removeSubclasses(Class[] classes)
+ {
+ List list = new ArrayList();
+ for (int i = 0; i < classes.length; i++)
+ {
+ Class candidate = classes[i];
+ boolean add = true;
+ for (int j = 0; j < classes.length; j++)
+ {
+ if (classes[j].equals(candidate))
+ continue;
+ else if (classes[j].isAssignableFrom(candidate))
+ add = false;
+ }
+ if (add) list.add(candidate);
+ }
+
+ return list;
+ }
+
+ public void intersectExceptions(Method m)
+ {
+ List incoming = removeSubclasses(m.getExceptionTypes());
+
+ List updated = new ArrayList();
+
+ for (int i = 0; i < exceptions.size(); i++)
+ {
+ Class outer = (Class) exceptions.get(i);
+ boolean addOuter = false;
+ for (int j = 0; j < incoming.size(); j++)
+ {
+ Class inner = (Class) incoming.get(j);
+
+ if (inner.equals(outer) || inner.isAssignableFrom(outer))
+ addOuter = true;
+ else if (outer.isAssignableFrom(inner))
+ updated.add(inner);
+ }
+
+ if (addOuter)
+ updated.add(outer);
+ }
+
+ exceptions = updated;
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/CompilationError.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/CompilationError.java
new file mode 100644
index 000000000..2bfea7cc4
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/CompilationError.java
@@ -0,0 +1,69 @@
+/* CompilationError.java -- Thrown on compilation error.
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+/**
+ * This error is thrown when the target being compiled has illegal
+ * strutures.
+ *
+ * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
+ */
+public class CompilationError extends Error
+{
+ /**
+ * Use serialVersionUID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Create error with explaining message and cause.
+ */
+ public CompilationError(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ /**
+ * Create error with explaining message
+ */
+ public CompilationError(String message)
+ {
+ super(message);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/Generator.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/Generator.java
new file mode 100644
index 000000000..ba659d2c5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/Generator.java
@@ -0,0 +1,145 @@
+/* Generator.java -- Generic code generator.
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Contains basic methods, used in code generation.
+ *
+ * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
+ */
+public class Generator
+{
+ /**
+ * Get resource with the given name, as string.
+ *
+ * @param name the resource name
+ * @return the resourse string (in subfolder /templates).
+ */
+ public String getResource(String name)
+ {
+ String resourcePath = "templates/" + name;
+ InputStream in = getClass().getResourceAsStream(resourcePath);
+
+ if (in == null)
+ throw new InternalError(getClass().getName() + ": no resource "
+ + resourcePath);
+
+ BufferedReader r = new BufferedReader(new InputStreamReader(in));
+ StringBuilder b = new StringBuilder();
+
+ String s;
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ b.append(s);
+ b.append('\n');
+ }
+ r.close();
+ }
+ catch (IOException e)
+ {
+ InternalError ierr = new InternalError("No expected resource " + name);
+ ierr.initCause(e);
+ throw ierr;
+ }
+
+ return b.toString();
+ }
+
+ /**
+ * Replace the variable references (starting from #) in the template string by
+ * the values, present in the given map. The strings, not present in the
+ * variable map, are ignored.
+ *
+ * @param template
+ * the template string
+ * @param variables
+ * the map of variables (name to value) to replace.
+ * @return the string with replaced values.
+ */
+ public String replaceAll(String template, Map variables)
+ {
+ BufferedReader r = new BufferedReader(new StringReader(template));
+ String s;
+ StringBuilder b = new StringBuilder(template.length());
+ try
+ {
+ Iterator iter;
+ Collection vars = variables.keySet();
+ while ((s = r.readLine()) != null)
+ {
+ // At least one variable must appear in the string to make
+ // the string scan sensible.
+ if (s.indexOf('#') >= 0)
+ {
+ iter = vars.iterator();
+ String variable;
+ while (iter.hasNext())
+ {
+ variable = (String) iter.next();
+ if (s.indexOf(variable) >= 0)
+ s = s.replaceAll(variable,
+ (String) variables.get(variable));
+ }
+ }
+ b.append(s);
+ b.append('\n');
+ }
+ r.close();
+ }
+ catch (IOException e)
+ {
+ // This should never happen.
+ InternalError ierr = new InternalError("");
+ ierr.initCause(e);
+ throw ierr;
+ }
+ return b.toString();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/GiopIo.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/GiopIo.java
new file mode 100644
index 000000000..c3b3bc0a4
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/GiopIo.java
@@ -0,0 +1,129 @@
+/* GiopIo.java -- Generates GIOP input/output statements.
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+import java.rmi.Remote;
+
+import org.omg.CORBA.portable.ObjectImpl;
+
+/**
+ * Generates the code for reading and writing data over GIOP stream.
+ *
+ * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
+ */
+public class GiopIo
+{
+ /**
+ * Get the statement for writing the variable of the given type to the GIOP ({@link org.omg.CORBA_2_3.portable.OutputStream) stream. The
+ * stream is always named "out".
+ *
+ * @param c
+ * the class of the object being written
+ * @param variable
+ * the variable, where the object value is stored
+ * @param r
+ * the parent generator, used to name the class
+ * @return the write statement.
+ */
+ public static String getWriteStatement(Class c, String variable, SourceGiopRmicCompiler r)
+ {
+ if (c.equals(boolean.class))
+ return "out.write_boolean(" + variable + ");";
+ if (c.equals(byte.class))
+ return "out.write_octet(" + variable + ");";
+ else if (c.equals(short.class))
+ return "out.write_int(" + variable + ");";
+ else if (c.equals(int.class))
+ return "out.write_long(" + variable + ");";
+ else if (c.equals(long.class))
+ return "out.write_long_long(" + variable + ");";
+ else if (c.equals(double.class))
+ return "out.write_double(" + variable + ");";
+ else if (c.equals(float.class))
+ return "out.write_float(" + variable + ");";
+ else if (c.equals(char.class))
+ return "out.write_char(" + variable + ");";
+ else if (Remote.class.isAssignableFrom(c))
+ return "Util.writeRemoteObject(out, " + variable + ");";
+ else if (ObjectImpl.class.isAssignableFrom(c))
+ return "out.write_Object(" + variable + ");";
+ else
+ return "out.write_value(" + variable + ", " + r.name(c) + ".class);";
+ }
+
+ /**
+ * Get the statement for reading the value of the given type from to the GIOP ({@link org.omg.CORBA_2_3.portable.InputStream) stream. The
+ * stream is always named "in".
+ *
+ * @param c
+ * the class of the object being written
+ * @param r
+ * the parent generator, used to name the class
+ * @return the right side of the read statement.
+ */
+ public static String getReadStatement(Class c, SourceGiopRmicCompiler r)
+ {
+ if (c.equals(boolean.class))
+ return "in.read_boolean();";
+ else if (c.equals(byte.class))
+ return "in.read_octet();";
+ else if (c.equals(short.class))
+ return "in.read_int();";
+ else if (c.equals(int.class))
+ return "in.read_long();";
+ else if (c.equals(long.class))
+ return "in.read_long_long();";
+ else if (c.equals(double.class))
+ return "in.read_double();";
+ else if (c.equals(float.class))
+ return "in.read_float();";
+ else if (c.equals(char.class))
+ return "in.read_char();";
+ else if (Remote.class.isAssignableFrom(c))
+ return "(" + r.name(c)
+ + ") PortableRemoteObject.narrow(in.read_Object()," + r.name(c)
+ + ".class);";
+ else if (ObjectImpl.class.isAssignableFrom(c))
+ return "in.read_Object();";
+ else
+ return "(" + r.name(c)
+ + ") in.read_value(" + r.name(c) + ".class);";
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/HashFinder.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/HashFinder.java
new file mode 100644
index 000000000..7b6fc9bb5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/HashFinder.java
@@ -0,0 +1,100 @@
+/* HashFinder.java -- finds the hash character.
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+import java.util.HashSet;
+
+/**
+ * This class finds the hash character (the most different character in
+ * the passed array of strings). This character is used to accelerate the
+ * method invocation by name.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class HashFinder
+{
+ /**
+ * Find the hash char position in the given collection of strings.
+ *
+ * @param strings the string collection
+ *
+ * @return the optimal hash character position, always less then the
+ * length of the shortest string.
+ */
+ public int findHashCharPosition(String[] strings)
+ {
+ // Find the length of the shortest string:
+
+ int l = strings[0].length();
+ for (int i = 1; i < strings.length; i++)
+ {
+ if (strings[i].length() < l)
+ l = strings[i].length();
+ }
+
+ // Find the position with the smallest number of the matching characters:
+ HashSet[] charLists = new HashSet[l];
+
+ for (int i = 0; i < charLists.length; i++)
+ {
+ charLists[i] = new HashSet(strings.length);
+ }
+
+ for (int i = 0; i < strings.length; i++)
+ for (int p = 0; p < l; p++)
+ {
+ charLists[p].add(new Integer(strings[i].charAt(p)));
+ }
+
+ int m = 0;
+ int v = charLists[0].size();
+
+ for (int i = 1; i < charLists.length; i++)
+ {
+ // Replace on equality also, seeking the hash char closer to the end
+ // of line.
+ if (charLists[i].size()>=v)
+ {
+ m = i;
+ v = charLists[i].size();
+ }
+ }
+ return m;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/Main.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/Main.java
new file mode 100644
index 000000000..868fc758e
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/Main.java
@@ -0,0 +1,293 @@
+/* Main.java -- RMI stub generator.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.util.ArrayList;
+
+/**
+ * Generates the ordinary stubs (not GIOP based) for java.rmi.* package.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class Main
+{
+ private boolean noWrite;
+ private boolean warnings = true;
+ private boolean verbose;
+ private boolean force;
+ private String classpath = ".";
+ private String outputDirectory = ".";
+ private boolean poa;
+ private boolean need11Stubs = false;
+ private boolean need12Stubs = true;
+ private boolean keep;
+ private boolean iiop;
+ /**
+ * Specifies whether or not JRMP mode was explicitly requested.
+ */
+ private boolean jrmp;
+
+ private Parser initializeParser()
+ {
+ Parser parser = new ClasspathToolParser("rmic", true); //$NON-NLS-1$
+ parser.setHeader(Messages.getString("Main.Usage")); //$NON-NLS-1$
+
+ parser.add(new Option("nowarn", //$NON-NLS-1$
+ Messages.getString("Main.NoWarn")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ warnings = false;
+ }
+ });
+ parser.add(new Option("nowrite", //$NON-NLS-1$
+ Messages.getString("Main.NoWrite")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ noWrite = true;
+ }
+ });
+ parser.add(new Option("verbose", //$NON-NLS-1$
+ Messages.getString("Main.Verbose")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ parser.add(new Option("d", //$NON-NLS-1$
+ Messages.getString("Main.DirOpt"), //$NON-NLS-1$
+ Messages.getString("Main.DirArg")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ outputDirectory = argument;
+ }
+ });
+ parser.add(new Option("classpath", //$NON-NLS-1$
+ Messages.getString("Main.ClasspathOpt"), //$NON-NLS-1$
+ Messages.getString("Main.ClasspathArg")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ classpath = argument;
+ }
+ });
+ parser.add(new Option("bootclasspath", //$NON-NLS-1$
+ Messages.getString("Main.BootclasspathOpt"), //$NON-NLS-1$
+ Messages.getString("Main.BootclasspathArg")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ }
+ });
+ parser.add(new Option("extdirs", //$NON-NLS-1$
+ Messages.getString("Main.ExtdirsOpt"), //$NON-NLS-1$
+ Messages.getString("Main.ExtdirsArg")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ }
+ });
+ parser.add(new Option("iiop", //$NON-NLS-1$
+ Messages.getString("Main.IIOP")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ iiop = true;
+ }
+ });
+ parser.add(new Option("always", //$NON-NLS-1$
+ Messages.getString("Main.Always")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ force = true;
+ }
+ });
+ parser.add(new Option("alwaysgenerate", //$NON-NLS-1$
+ Messages.getString("Main.AlwaysGenerate")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ force = true;
+ }
+ });
+ parser.add(new Option("nolocalstubs", //$NON-NLS-1$
+ Messages.getString("Main.NoLocalStubs")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ }
+ });
+ parser.add(new Option("poa", //$NON-NLS-1$
+ Messages.getString("Main.POA")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ poa = true;
+ }
+ });
+ parser.add(new Option("keep", //$NON-NLS-1$
+ Messages.getString("Main.Keep")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ keep = true;
+ }
+ });
+ parser.add(new Option("keepgenerated", //$NON-NLS-1$
+ Messages.getString("Main.KeepGenerated")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ keep = true;
+ }
+ });
+ parser.add(new Option("v1.1", //$NON-NLS-1$
+ Messages.getString("Main.v11")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ need11Stubs = true;
+ need12Stubs = false;
+ jrmp = true;
+ }
+ });
+ parser.add(new Option("v1.2", //$NON-NLS-1$
+ Messages.getString("Main.v12")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ jrmp = true;
+ }
+ });
+ parser.add(new Option("vcompat", //$NON-NLS-1$
+ Messages.getString("Main.vcompat")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ need11Stubs = true;
+ need12Stubs = true;
+ jrmp = true;
+ }
+ });
+ parser.add(new Option("g", //$NON-NLS-1$
+ Messages.getString("Main.DebugInfo")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ }
+ });
+
+ return parser;
+ }
+
+ private void run(String[] args)
+ {
+ Parser p = initializeParser();
+ String[] files = p.parse(args);
+
+ if (files.length == 0)
+ {
+ p.printHelp();
+ System.exit(1);
+ }
+
+ ArrayList backends = new ArrayList();
+
+ // FIXME: need an IDL RmicBackend
+ // FIXME: need a ClassGiopRmicCompiler RmicBackend
+ if (iiop)
+ {
+ backends.add(new SourceGiopRmicCompiler());
+
+ if (jrmp)
+ {
+ // Both IIOP and JRMP stubs were requested.
+ backends.add(new ClassRmicCompiler());
+ // FIXME: SourceRmicCompiler should support v1.1
+ if (keep)
+ backends.add(new SourceRmicCompiler());
+ }
+ }
+ else
+ {
+ backends.add(new ClassRmicCompiler());
+ if (keep)
+ backends.add(new SourceRmicCompiler());
+ }
+
+ for (int i = 0; i < backends.size(); i++)
+ {
+ RmicBackend b = (RmicBackend) backends.get(i);
+ b.setup(keep, need11Stubs, need12Stubs,
+ iiop, poa, false, warnings,
+ noWrite, verbose, force, classpath,
+ null, null, outputDirectory);
+ if (!b.run(files))
+ System.exit(1);
+ }
+ }
+
+ /**
+ * The RMI compiler entry point.
+ */
+ public static void main(String[] args)
+ {
+ Main rmicprogram = new Main();
+ try
+ {
+ rmicprogram.run(args);
+ }
+ catch (Exception e)
+ {
+ System.err.println(Messages.getString("Main.InternalError")); //$NON-NLS-1$
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/Messages.java
new file mode 100644
index 000000000..5e67dd163
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- localization support for rmic
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.rmic.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/MethodGenerator.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/MethodGenerator.java
new file mode 100644
index 000000000..27a4bd2e1
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/MethodGenerator.java
@@ -0,0 +1,302 @@
+/* MethodGenerator.java -- Generates methods for GIOP rmic compiler.
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+import gnu.classpath.tools.rmic.AbstractMethodGenerator;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+/**
+ * Keeps information about the single method and generates the code fragments,
+ * related to that method.
+ *
+ * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
+ */
+public class MethodGenerator implements AbstractMethodGenerator
+{
+ /**
+ * The method being defined.
+ */
+ Method method;
+
+ /**
+ * The parent code generator.
+ */
+ SourceGiopRmicCompiler rmic;
+
+ /**
+ * The previous method in the list, null for the first element.
+ * Used to avoid repretetive inclusion of the same hash code label.
+ */
+ MethodGenerator previous = null;
+
+ /**
+ * The hash character position.
+ */
+ int hashCharPosition;
+
+ /**
+ * Create the new method generator for the given method.
+ *
+ * @param aMethod
+ * the related method.
+ * @param aRmic
+ * the Rmic generator instance, where more class - related
+ * information is defined.
+ */
+ public MethodGenerator(Method aMethod, SourceGiopRmicCompiler aRmic)
+ {
+ method = aMethod;
+ rmic = aRmic;
+ }
+
+ /**
+ * Get the method name.
+ *
+ * @return the name of the method.
+ */
+ public String getGiopMethodName()
+ {
+ String m = method.getName();
+ if (m.startsWith("get"))
+ return "_get_J" + m.substring("get".length());
+ else if (m.startsWith("set"))
+ return "_set_J" + m.substring("set".length());
+ else
+ return m;
+ }
+
+ /**
+ * Get the method parameter declaration.
+ *
+ * @return the string - method parameter declaration.
+ */
+ public String getArgumentList()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(rmic.name(args[i]));
+ b.append(" p" + i);
+ if (i < args.length - 1)
+ b.append(", ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the method parameter list only (no type declarations). This is used to
+ * generate the method invocations statement.
+ *
+ * @return the string - method parameter list.
+ */
+ public String getArgumentNames()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(" p" + i);
+ if (i < args.length - 1)
+ b.append(", ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the list of exceptions, thrown by this method.
+ *
+ * @return the list of exceptions.
+ */
+ public String getThrows()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Class[] args = method.getExceptionTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(rmic.name(args[i]));
+ if (i < args.length - 1)
+ b.append(", ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Generate this method for the Stub class.
+ *
+ * @return the method body for the stub class.
+ */
+ public String generateStubMethod()
+ {
+ String templateName;
+
+ Properties vars = new Properties(rmic.vars);
+ vars.put("#return_type", rmic.name(method.getReturnType()));
+ vars.put("#method_name", method.getName());
+ vars.put("#giop_method_name", getGiopMethodName());
+ vars.put("#argument_list", getArgumentList());
+ vars.put("#argument_names", getArgumentNames());
+
+ vars.put("#argument_write", getStubParaWriteStatement());
+
+ if (method.getReturnType().equals(void.class))
+ vars.put("#read_return", "return;");
+ else
+ vars.put("#read_return",
+ "return "
+ + GiopIo.getReadStatement(method.getReturnType(), rmic));
+ String thr = getThrows();
+ if (thr.length() > 0)
+ vars.put("#throws", "\n throws " + thr);
+ else
+ vars.put("#throws", "");
+
+ if (method.getReturnType().equals(void.class))
+ templateName = "StubMethodVoid.jav";
+ else
+ {
+ vars.put("#write_result",
+ GiopIo.getWriteStatement(method.getReturnType(), "result",
+ rmic));
+ templateName = "StubMethod.jav";
+ }
+
+ String template = rmic.getResource(templateName);
+ String generated = rmic.replaceAll(template, vars);
+ return generated;
+ }
+
+ /**
+ * Generate this method handling fragment for the Tie class.
+ *
+ * @return the fragment to handle this method for the Tie class.
+ */
+ public String generateTieMethod()
+ {
+ String templateName;
+
+ Properties vars = new Properties(rmic.vars);
+ vars.put("#return_type", rmic.name(method.getReturnType()));
+ vars.put("#method_name", method.getName());
+ vars.put("#giop_method_name", getGiopMethodName());
+ vars.put("#argument_list", getArgumentList());
+ vars.put("#argument_names", getArgumentNames());
+
+ vars.put("#argument_write", getStubParaWriteStatement());
+
+ if (previous == null || previous.getHashChar()!=getHashChar())
+ vars.put("#hashCodeLabel"," case '"+getHashChar()+"':");
+ else
+ vars.put("#hashCodeLabel"," // also '"+getHashChar()+"':");
+
+ if (method.getReturnType().equals(void.class))
+ templateName = "TieMethodVoid.jav";
+ else
+ {
+ vars.put("#write_result",
+ GiopIo.getWriteStatement(method.getReturnType(), "result",
+ rmic));
+ templateName = "TieMethod.jav";
+ }
+ vars.put("#read_and_define_args", getRda());
+
+ String template = rmic.getResource(templateName);
+ String generated = rmic.replaceAll(template, vars);
+ return generated;
+ }
+
+ /**
+ * Generate sentences for Reading and Defining Arguments.
+ *
+ * @return the sequence of sentences for reading and defining arguments.
+ */
+ public String getRda()
+ {
+ StringBuilder b = new StringBuilder();
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(" ");
+ b.append(rmic.name(args[i]));
+ b.append(" ");
+ b.append("p"+i);
+ b.append(" = ");
+ b.append(GiopIo.getReadStatement(args[i], rmic));
+ if (i<args.length-1)
+ b.append("\n");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the write statement for writing parameters inside the stub.
+ *
+ * @return the write statement.
+ */
+ public String getStubParaWriteStatement()
+ {
+ StringBuilder b = new StringBuilder();
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(" ");
+ b.append(GiopIo.getWriteStatement(args[i], "p" + i, rmic));
+ b.append("\n");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the hash char.
+ */
+ public char getHashChar()
+ {
+ return getGiopMethodName().charAt(hashCharPosition);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/RMICException.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/RMICException.java
new file mode 100644
index 000000000..ca9983d0a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/RMICException.java
@@ -0,0 +1,70 @@
+/* RMICException.java --
+ Copyright (c) 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmic;
+
+/**
+ * Thrown by the underlying compiler used by RMIC when it fails to compile a
+ * file.
+ *
+ * @author Dalibor Topic (robilad@kaffe.org)
+ */
+public class RMICException
+ extends Exception
+{
+ /**
+ * Create an exception with a message. The cause remains uninitialized.
+ *
+ * @param message the message string
+ * @see #initCause(Throwable)
+ */
+ public RMICException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create an exception with a message and a cause.
+ *
+ * @param message the message string
+ * @param cause the cause of this exception
+ */
+ public RMICException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/RmiMethodGenerator.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/RmiMethodGenerator.java
new file mode 100644
index 000000000..e02f086ef
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/RmiMethodGenerator.java
@@ -0,0 +1,297 @@
+/* MethodGenerator.java -- Generates methods for rmi compiler.
+ Copyright (C) 2006 Free Software Foundation
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+package gnu.classpath.tools.rmic;
+
+import gnu.classpath.tools.rmic.AbstractMethodGenerator;
+import gnu.java.rmi.server.RMIHashes;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+/**
+ * Keeps information about the single method and generates the code fragments,
+ * related to that method.
+ *
+ * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
+ */
+public class RmiMethodGenerator
+ implements AbstractMethodGenerator
+{
+ /**
+ * The method being defined.
+ */
+ Method method;
+
+ /**
+ * The parent code generator.
+ */
+ SourceRmicCompiler rmic;
+
+ /**
+ * Create the new method generator for the given method.
+ *
+ * @param aMethod the related method.
+ * @param aRmic the Rmic generator instance, where more class - related
+ * information is defined.
+ */
+ public RmiMethodGenerator(Method aMethod, SourceRmicCompiler aRmic)
+ {
+ method = aMethod;
+ rmic = aRmic;
+ if (method.getParameterTypes().length == 0)
+ rmic.addZeroSizeObjecArray = true;
+ }
+
+ /**
+ * Get the method parameter declaration.
+ *
+ * @return the string - method parameter declaration.
+ */
+ public String getArgumentList()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(rmic.name(args[i]));
+ b.append(" p" + i);
+ if (i < args.length - 1)
+ b.append(", ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the method parameter list only (no type declarations). This is used to
+ * generate the method invocations statement.
+ *
+ * @return the string - method parameter list.
+ */
+ public String getArgumentNames()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(" p" + i);
+ if (i < args.length - 1)
+ b.append(", ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the list of exceptions, thrown by this method.
+ *
+ * @return the list of exceptions.
+ */
+ public String getThrows()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Class[] args = method.getExceptionTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(rmic.name(args[i]));
+ if (i < args.length - 1)
+ b.append(", ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Generate this method for the Stub class.
+ *
+ * @return the method body for the stub class.
+ */
+ public String generateStubMethod()
+ {
+ String templateName;
+
+ Properties vars = new Properties(rmic.vars);
+ vars.put("#return_type", rmic.name(method.getReturnType()));
+ vars.put("#method_name", method.getName());
+ vars.put("#method_hash", getMethodHashCode());
+ vars.put("#argument_list", getArgumentList());
+ vars.put("#object_arg_list", getArgListAsObjectArray());
+ vars.put("#declaring_class", rmic.name(method.getDeclaringClass()));
+ vars.put("#class_arg_list", getArgListAsClassArray());
+
+ String thr = getThrows();
+ if (thr.length() > 0)
+ vars.put("#throws", "\n throws " + thr);
+ else
+ vars.put("#throws", "");
+
+ if (method.getReturnType().equals(void.class))
+ templateName = "Stub_12MethodVoid.jav";
+ else
+ {
+ templateName = "Stub_12Method.jav";
+ vars.put("#return_statement", getReturnStatement());
+ }
+
+ String template = rmic.getResource(templateName);
+ String generated = rmic.replaceAll(template, vars);
+ return generated;
+ }
+
+ /**
+ * Generate sentences for Reading and Defining Arguments.
+ *
+ * @return the sequence of sentences for reading and defining arguments.
+ */
+ public String getStaticMethodDeclarations()
+ {
+ StringBuilder b = new StringBuilder();
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(" ");
+ b.append(rmic.name(args[i]));
+ b.append(" ");
+ b.append("p" + i);
+ b.append(" = ");
+ if (i < args.length - 1)
+ b.append("\n");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the write statement for writing parameters inside the stub.
+ *
+ * @return the write statement.
+ */
+ public String getArgListAsObjectArray()
+ {
+ Class[] args = method.getParameterTypes();
+
+ if (args.length==0)
+ return "NO_ARGS";
+
+ StringBuilder b = new StringBuilder("new Object[] {");
+
+ for (int i = 0; i < args.length; i++)
+ {
+ if (!args[i].isPrimitive())
+ b.append("p"+i);
+ else
+ {
+ b.append("new "+rmic.name(WrapUnWrapper.getWrappingClass(args[i])));
+ b.append("(p"+i+")");
+ }
+ if (i<args.length-1)
+ b.append(", ");
+ }
+ b.append("}");
+ return b.toString();
+ }
+
+ /**
+ * Get the return statement, assuming that the returned object is placed into
+ * the variable "result".
+ */
+ public String getReturnStatement()
+ {
+ Class r = method.getReturnType();
+ if (r.equals(void.class))
+ return "";
+ else
+ {
+ if (r.isPrimitive())
+ {
+ String wcd = rmic.name(WrapUnWrapper.getWrappingClass(r));
+ return "return ((" + wcd + ") result)."
+ + WrapUnWrapper.getUnwrappingMethod(r) + ";";
+ }
+ else
+ return "return (" + rmic.name(r) + ") result;";
+ }
+ }
+
+ /**
+ * Get argument list as class array.
+ */
+ public String getArgListAsClassArray()
+ {
+ StringBuilder b = new StringBuilder();
+ Class[] args = method.getParameterTypes();
+
+ for (int i = 0; i < args.length; i++)
+ {
+ b.append(rmic.name(args[i]));
+ b.append(".class");
+ if (i < args.length - 1)
+ b.append(", ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * RMI ties (previously named Skeletons) are no longer used since v 1.2. This
+ * method should never be called.
+ */
+ public String generateTieMethod()
+ {
+ throw new InternalError();
+ }
+
+ /**
+ * Get the method hash code.
+ */
+ public String getMethodHashCode()
+ {
+ return RMIHashes.getMethodHash(method)+"L";
+ }
+
+ /**
+ * Additional processing of the stub name (nothing to do for JRMP stubs).
+ */
+ public String convertStubName(String name)
+ {
+ return name;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/RmicBackend.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/RmicBackend.java
new file mode 100644
index 000000000..92f982d53
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/RmicBackend.java
@@ -0,0 +1,48 @@
+/* RmicBackend.java --
+ Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmic;
+public interface RmicBackend
+{
+ void setup(boolean keep, boolean need11Stubs, boolean need12Stubs,
+ boolean iiop, boolean poa, boolean debug, boolean warnings,
+ boolean noWrite, boolean verbose, boolean force, String classpath,
+ String bootclasspath, String extdirs, String outputDirectory);
+
+ boolean run(String[] inputFiles);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java
new file mode 100644
index 000000000..dd35c2bd5
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/SourceGiopRmicCompiler.java
@@ -0,0 +1,694 @@
+/* SourceGiopRmicCompiler -- Central GIOP-based RMI stub and tie compiler class.
+ Copyright (C) 2006, 2008 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+*/
+
+package gnu.classpath.tools.rmic;
+
+import gnu.classpath.tools.rmic.AbstractMethodGenerator;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+/**
+ * Provides the extended rmic functionality to generate the POA - based classes
+ * for GIOP (javax.rmi.CORBA package).
+ *
+ * @author Audrius Meskauskas, Lithuania (audriusa@Bioinformatics.org)
+ */
+public class SourceGiopRmicCompiler
+ extends Generator implements Comparator, RmicBackend
+{
+ /** The package name. */
+ protected String packag;
+
+ /**
+ * The "basic" name (normally, the interface name, unless several Remote -
+ * derived interfaces are implemented.
+ */
+ protected String name;
+
+ /**
+ * The name (without package) of the class, passed as the parameter.
+ */
+ protected String implName;
+
+ /**
+ * The proposed name for the stub.
+ */
+ protected String stubName;
+
+ /**
+ * The Remote's, implemented by this class.
+ */
+ protected Collection implementedRemotes = new HashSet();
+
+ /**
+ * The extra classes that must be imported.
+ */
+ protected Collection extraImports = new HashSet();
+
+ /**
+ * The methods we must implement.
+ */
+ protected Collection methods = new HashSet();
+
+ /**
+ * The map of all code generator variables.
+ */
+ public Properties vars = new Properties();
+
+ /**
+ * If this flag is set (true by default), the compiler generates the Servant
+ * based classes. If set to false, the compiler generates the old style
+ * ObjectImpl based classes.
+ */
+ protected boolean poaMode = true;
+
+ /**
+ * If this flag is set (true by default), the compiler emits warnings.
+ */
+ protected boolean warnings = true;
+
+ /**
+ * If this flag is set (false by default), the compiler does not
+ * write output files.
+ */
+ protected boolean noWrite = false;
+
+ /**
+ * If this flag is set (false by default), the compiler keeps source
+ * output files. For SourceGiopRmicCompiler this overrides
+ * -nowrite, since -nowrite doesn't apply to sources kept with
+ * -keep.
+ */
+ protected boolean keep = false;
+
+ /**
+ * Verbose output
+ */
+ protected boolean verbose = false;
+
+ /**
+ * Force mode - do not check the exceptions
+ */
+ protected boolean force = false;
+
+ /**
+ * The output directory for generated files.
+ */
+ protected String outputDirectory;
+
+ /**
+ * The class loader to load the class being compiled.
+ */
+ ClassLoader classLoader;
+
+ /**
+ * Clear data, preparing for the next compilation.
+ */
+ public synchronized void reset()
+ {
+ packag = name = implName = stubName = null;
+ implementedRemotes.clear();
+ extraImports.clear();
+ methods.clear();
+ vars.clear();
+ }
+
+ /**
+ * Set the class path (handle the -classpath key)
+ *
+ * @param classPath the class path to set.
+ */
+ public void setClassPath(String classPath)
+ {
+ classLoader = Thread.currentThread().getContextClassLoader();
+ StringTokenizer tok = new StringTokenizer(classPath, File.pathSeparator,
+ true);
+ ArrayList urls = new ArrayList(tok.countTokens());
+ String s = null;
+ try
+ {
+ while (tok.hasMoreTokens())
+ {
+ s = tok.nextToken();
+ if (s.equals(File.pathSeparator))
+ urls.add(new File(".").toURL());
+ else
+ {
+ urls.add(new File(s).toURL());
+ if (tok.hasMoreTokens())
+ {
+ // Skip the separator.
+ tok.nextToken();
+ // If the classpath ended with a separator,
+ // append the current directory.
+ if (! tok.hasMoreTokens())
+ urls.add(new File(".").toURL());
+ }
+ }
+ }
+ }
+ catch (MalformedURLException ex)
+ {
+ System.err.println("Malformed path '" + s + "' in classpath '"
+ + classPath + "'");
+ System.exit(1);
+ }
+ URL[] u = new URL[urls.size()];
+ for (int i = 0; i < u.length; i++)
+ {
+ u[i] = (URL) urls.get(i);
+ }
+
+ classLoader = new URLClassLoader(u, classLoader);
+ }
+
+ /**
+ * Loads the class with the given name (uses class path, if applicable)
+ *
+ * @param name the name of the class.
+ */
+ public Class loadClass(String name)
+ {
+ ClassLoader loader = classLoader;
+ if (loader == null)
+ loader = Thread.currentThread().getContextClassLoader();
+ try
+ {
+ return loader.loadClass(name);
+ }
+ catch (ClassNotFoundException e)
+ {
+ System.err.println(name+" not found on "+loader);
+ System.exit(1);
+ // Unreacheable code.
+ return null;
+ }
+ }
+
+ /**
+ * Compile the given class (the instance of Remote), generating the stub and
+ * tie for it.
+ *
+ * @param remote
+ * the class to compile.
+ */
+ public synchronized void compile(Class remote)
+ {
+ reset();
+ String s;
+
+ // Get the package.
+ s = remote.getName();
+ int p = s.lastIndexOf('.');
+ if (p < 0)
+ {
+ // Root package.
+ packag = "";
+ implName = name = s;
+ }
+ else
+ {
+ packag = s.substring(0, p);
+ implName = name = s.substring(p + 1);
+ }
+
+ name = convertStubName(name);
+
+ stubName = name;
+
+ vars.put("#name", name);
+ vars.put("#package", packag);
+ vars.put("#implName", implName);
+
+ if (verbose)
+ System.out.println("Package " + packag + ", name " + name + " impl "
+ + implName);
+
+ // Get the implemented remotes.
+ Class[] interfaces = remote.getInterfaces();
+
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ if (Remote.class.isAssignableFrom(interfaces[i]))
+ {
+ if (! interfaces[i].equals(Remote.class))
+ {
+ implementedRemotes.add(interfaces[i]);
+ }
+ }
+ }
+
+ vars.put("#idList", getIdList(implementedRemotes));
+
+ // Collect and process methods.
+ Iterator iter = implementedRemotes.iterator();
+
+ while (iter.hasNext())
+ {
+ Class c = (Class) iter.next();
+ Method[] m = c.getMethods();
+
+ // Check if throws RemoteException.
+ for (int i = 0; i < m.length; i++)
+ {
+ Class[] exc = m[i].getExceptionTypes();
+ boolean remEx = false;
+
+ for (int j = 0; j < exc.length; j++)
+ {
+ if (exc[j].isAssignableFrom(RemoteException.class))
+ {
+ remEx = true;
+ break;
+ }
+ }
+ if (! remEx && !force)
+ throw new CompilationError(m[i].getName() + ", defined in "
+ + c.getName()
+ + ", does not throw "
+ + RemoteException.class.getName());
+ AbstractMethodGenerator mm = createMethodGenerator(m[i]);
+ methods.add(mm);
+ }
+ }
+ }
+
+ /**
+ * Create the method generator for the given method.
+ *
+ * @param m the method
+ *
+ * @return the created method generator
+ */
+ protected AbstractMethodGenerator createMethodGenerator(Method m)
+ {
+ return new MethodGenerator(m, this);
+ }
+
+ /**
+ * Get the name of the given class. The class is added to imports, if not
+ * already present and not from java.lang and not from the current package.
+ *
+ * @param nameIt
+ * the class to name
+ * @return the name of class as it should appear in java language
+ */
+ public synchronized String name(Class nameIt)
+ {
+ if (nameIt.isArray())
+ {
+ // Mesure dimensions:
+ int dimension = 0;
+ Class finalComponent = nameIt;
+ while (finalComponent.isArray())
+ {
+ finalComponent = finalComponent.getComponentType();
+ dimension++;
+ }
+
+ StringBuilder brackets = new StringBuilder();
+
+ for (int i = 0; i < dimension; i++)
+ {
+ brackets.append("[]");
+ }
+
+ return name(finalComponent) + " " + brackets;
+ }
+ else
+ {
+ String n = nameIt.getName();
+ if (! nameIt.isArray() && ! nameIt.isPrimitive())
+ if (! n.startsWith("java.lang")
+ && ! (packag != null && n.startsWith(packag)))
+ extraImports.add(n);
+
+ int p = n.lastIndexOf('.');
+ if (p < 0)
+ return n;
+ else
+ return n.substring(p + 1);
+ }
+ }
+
+ /**
+ * Get the RMI-style repository Id for the given class.
+ *
+ * @param c
+ * the interface, for that the repository Id must be created.
+ * @return the repository id
+ */
+ public String getId(Class c)
+ {
+ return "RMI:" + c.getName() + ":0000000000000000";
+ }
+
+ /**
+ * Get repository Id string array declaration.
+ *
+ * @param remotes
+ * the collection of interfaces
+ * @return the fully formatted string array.
+ */
+ public String getIdList(Collection remotes)
+ {
+ StringBuilder b = new StringBuilder();
+
+ // Keep the Ids sorted, ensuring, that the same order will be preserved
+ // between compilations.
+ TreeSet sortedIds = new TreeSet();
+
+ Iterator iter = remotes.iterator();
+ while (iter.hasNext())
+ {
+ sortedIds.add(getId((Class) iter.next()));
+ }
+
+ iter = sortedIds.iterator();
+ while (iter.hasNext())
+ {
+ b.append(" \"" + iter.next() + "\"");
+ if (iter.hasNext())
+ b.append(", \n");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Generate stub. Can only be called from {@link #compile}.
+ *
+ * @return the string, containing the text of the generated stub.
+ */
+ public String generateStub()
+ {
+ String template = getResource("Stub.jav");
+
+ // Generate methods.
+ StringBuilder b = new StringBuilder();
+ Iterator iter = methods.iterator();
+ while (iter.hasNext())
+ {
+ AbstractMethodGenerator m = (AbstractMethodGenerator) iter.next();
+ b.append(m.generateStubMethod());
+ }
+
+ vars.put("#stub_methods", b.toString());
+ vars.put("#imports", getImportStatements());
+ vars.put("#interfaces", getAllInterfaces());
+
+ String output = replaceAll(template, vars);
+ return output;
+ }
+
+ /**
+ * Get the list of all interfaces, implemented by the class, that are
+ * derived from Remote.
+ *
+ * @return the string - all interfaces.
+ */
+ public String getAllInterfaces()
+ {
+ StringBuilder b = new StringBuilder();
+ Iterator iter = implementedRemotes.iterator();
+
+ while (iter.hasNext())
+ {
+ b.append(name((Class) iter.next()));
+ if (iter.hasNext())
+ b.append(", ");
+ }
+
+ return b.toString();
+ }
+
+ /**
+ * Generate Tie. Can only be called from {@link #compile}.
+ *
+ * @return the string, containing the text of the generated Tie.
+ */
+ public String generateTie()
+ {
+ String template;
+ if (poaMode)
+ template = getResource("Tie.jav");
+ else
+ template = getResource("ImplTie.jav");
+
+ // Generate methods.
+ HashFinder hashFinder = new HashFinder();
+
+ // Find the hash character position:
+ Iterator iter = methods.iterator();
+ String[] names = new String[methods.size()];
+ int p = 0;
+
+ for (int i = 0; i < names.length; i++)
+ names[i] = ((MethodGenerator) iter.next()).getGiopMethodName();
+
+ int hashCharPosition = hashFinder.findHashCharPosition(names);
+
+ iter = methods.iterator();
+ while (iter.hasNext())
+ ((MethodGenerator) iter.next()).hashCharPosition = hashCharPosition;
+
+ vars.put("#hashCharPos", Integer.toString(hashCharPosition));
+
+ ArrayList sortedMethods = new ArrayList(methods);
+ Collections.sort(sortedMethods, this);
+
+ iter = sortedMethods.iterator();
+
+ StringBuilder b = new StringBuilder();
+
+ MethodGenerator prev = null;
+
+ while (iter.hasNext())
+ {
+ MethodGenerator m = (MethodGenerator) iter.next();
+ m.previous = prev;
+ m.hashCharPosition = hashCharPosition;
+ prev = m;
+ b.append(m.generateTieMethod());
+ }
+
+ vars.put("#tie_methods", b.toString());
+
+ vars.put("#imports", getImportStatements());
+
+ String output = replaceAll(template, vars);
+ return output;
+ }
+
+ public int compare(Object a, Object b)
+ {
+ MethodGenerator g1 = (MethodGenerator) a;
+ MethodGenerator g2 = (MethodGenerator) b;
+
+ return g1.getHashChar() - g2.getHashChar();
+ }
+
+ /**
+ * Import the extra classes, used as the method parameters and return values.
+ *
+ * @return the additional import block.
+ */
+ protected String getImportStatements()
+ {
+ TreeSet imp = new TreeSet();
+
+ Iterator it = extraImports.iterator();
+ while (it.hasNext())
+ {
+ String ic = it.next().toString();
+ imp.add("import " + ic + ";\n");
+ }
+
+ StringBuilder b = new StringBuilder();
+ it = imp.iterator();
+
+ while (it.hasNext())
+ {
+ b.append(it.next());
+ }
+ return b.toString();
+ }
+
+ /**
+ * If this flag is set (true by default), the compiler generates the Servant
+ * based classes. If set to false, the compiler generates the old style
+ * ObjectImpl based classes.
+ */
+ public void setPoaMode(boolean mode)
+ {
+ poaMode = mode;
+ }
+
+ /**
+ * Set the verbose output mode (false by default)
+ *
+ * @param isVerbose the verbose output mode
+ */
+ public void setVerbose(boolean isVerbose)
+ {
+ verbose = isVerbose;
+ }
+
+ /**
+ * If this flag is set (true by default), the compiler emits warnings.
+ */
+ public void setWarnings(boolean warn)
+ {
+ warnings = warn;
+ }
+
+ /**
+ * Set the error ignore mode.
+ */
+ public void setForce(boolean isforce)
+ {
+ force = isforce;
+ }
+
+ /**
+ * Get the package name.
+ */
+ public String getPackageName()
+ {
+ return packag;
+ }
+
+ /**
+ * Get the proposed stub name
+ */
+ public String getStubName()
+ {
+ return stubName;
+ }
+
+ /**
+ * Additional processing of the stub name.
+ */
+ public String convertStubName(String name)
+ {
+ // Drop the Impl suffix, if one exists.
+ if (name.endsWith("Impl"))
+ return name.substring(0, name.length() - "Impl".length());
+ else
+ return name;
+ }
+
+ /**
+ * Assumes that output directory is already created.
+ */
+ protected boolean outputTie(File fw, Class c)
+ {
+ try
+ {
+ String tie = generateTie();
+ String tieName = "_" + name(c) + "_Tie.java";
+
+ OutputStream out = new FileOutputStream(new File(fw, tieName));
+ out.write(tie.getBytes());
+ out.close();
+ }
+ catch (IOException ioex)
+ {
+ System.err.println("Output path not accessible");
+ ioex.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ public void setup(boolean keep, boolean need11Stubs, boolean need12Stubs,
+ boolean iiop, boolean poa, boolean debug, boolean warnings,
+ boolean noWrite, boolean verbose, boolean force, String classpath,
+ String bootclasspath, String extdirs, String outputDirectory)
+ {
+ setWarnings(warnings);
+ setVerbose(verbose);
+ setForce(force);
+ setClassPath(classpath);
+ setPoaMode(poa);
+ this.outputDirectory = outputDirectory;
+ this.noWrite = noWrite;
+ this.keep = keep;
+ }
+
+ public boolean run(String[] inputFiles)
+ {
+ for (int i = 0; i < inputFiles.length; i++)
+ {
+ reset();
+ Class c = loadClass(inputFiles[i]);
+
+ compile(c);
+ String packag = getPackageName().replace('.', '/');
+ File fw = new File(outputDirectory, packag);
+
+ // Generate stub.
+ String stub = generateStub();
+ String subName = getStubName() + "_Stub.java";
+
+ // -keep overrides -nowrite for sources.
+ if (!noWrite || keep)
+ {
+ try
+ {
+ fw.mkdirs();
+ OutputStream out = new FileOutputStream(new File(fw,
+ subName));
+ out.write(stub.getBytes());
+ out.close();
+
+ // Generate tie
+ if (!outputTie(fw, c))
+ return false;
+ }
+ catch (IOException ioex)
+ {
+ System.err.println("Output path not accessible");
+ ioex.printStackTrace();
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/SourceRmicCompiler.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/SourceRmicCompiler.java
new file mode 100644
index 000000000..413d91ad2
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/SourceRmicCompiler.java
@@ -0,0 +1,189 @@
+/* SourceRmicCompiler.java -- RMI stub generator for java.rmi.*
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmic;
+
+import java.lang.reflect.Method;
+import java.io.File;
+import java.util.Iterator;
+
+import gnu.classpath.tools.rmic.AbstractMethodGenerator;
+
+/**
+ * RMI stub source code generator, required to support java.rmi.*
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class SourceRmicCompiler extends SourceGiopRmicCompiler
+{
+ /**
+ * If true, the zero size object array is declared in the stub to reduce
+ * garbage generation.
+ */
+ public boolean addZeroSizeObjecArray;
+
+ /**
+ * Generate a RMI stub.
+ *
+ * @return the string, containing the text of the generated stub.
+ */
+ public String generateStub()
+ {
+ String template = getResource("Stub_12.jav");
+
+ // Generate methods.
+ StringBuilder b = new StringBuilder();
+ Iterator iter = methods.iterator();
+ while (iter.hasNext())
+ {
+ RmiMethodGenerator m = (RmiMethodGenerator) iter.next();
+ b.append(m.generateStubMethod());
+ }
+
+ vars.put("#stub_methods", b.toString());
+ vars.put("#imports", getImportStatements());
+ vars.put("#interfaces", getAllInterfaces());
+ vars.put("#stub_method_declarations", getStubMethodDeclarations());
+ vars.put("#stub_method_initializations", getStubMethodInitializations());
+ if (addZeroSizeObjecArray)
+ {
+ vars.put("#zeroSizeObjecArray",
+ "private static final Object[] NO_ARGS = new Object[0];");
+ vars.put("#zeroSizeClassArray",
+ "final Class[] NO_ARGSc = new Class[0];");
+ }
+ else
+ {
+ vars.put("#zeroSizeObjecArray","");
+ vars.put("#zeroSizeClassArray","");
+ }
+
+ String output = replaceAll(template, vars);
+ return output;
+ }
+
+ /**
+ * Create a method generator, applicable for RMI stub methods.
+ */
+ protected AbstractMethodGenerator createMethodGenerator(Method m)
+ {
+ return new RmiMethodGenerator(m, this);
+ }
+
+ /**
+ * Get the stub method declarations.
+ */
+ public String getStubMethodDeclarations()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Iterator iter = methods.iterator();
+
+ while (iter.hasNext())
+ {
+ RmiMethodGenerator method = (RmiMethodGenerator) iter.next();
+ b.append(" ");
+ b.append("private static final Method met_");
+ b.append(method.method.getName());
+ b.append(';');
+ if (iter.hasNext())
+ b.append('\n');
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get stub method initializations. These must be done in a try-catch
+ * statement to catch {@link NoSuchMethodException}.
+ */
+ public String getStubMethodInitializations()
+ {
+ StringBuilder b = new StringBuilder();
+
+ Iterator iter = methods.iterator();
+
+ while (iter.hasNext())
+ {
+ RmiMethodGenerator method = (RmiMethodGenerator) iter.next();
+ b.append(" ");
+ b.append("met_");
+ b.append(method.method.getName());
+ b.append(" =\n ");
+ b.append(name(method.method.getDeclaringClass()));
+ b.append(".class.getMethod(");
+ b.append('"');
+ b.append(method.method.getName());
+ b.append("\", ");
+ if (method.method.getParameterTypes().length == 0)
+ b.append("NO_ARGSc);");
+ else
+ {
+ b.append("new Class[]\n {\n ");
+ b.append(method.getArgListAsClassArray());
+ b.append("\n }");
+ b.append(");");
+ }
+ b.append('\n');
+ }
+ return b.toString();
+ }
+
+ /**
+ * Prepare for the compilation of the next class.
+ */
+ public void reset()
+ {
+ addZeroSizeObjecArray = false;
+ super.reset();
+ }
+
+ /**
+ * Additional processing of the stub name (nothing to do for JRMP stubs).
+ */
+ public String convertStubName(String name)
+ {
+ return name;
+ }
+
+ /**
+ * Override to do nothing.
+ */
+ protected boolean outputTie(File fw, Class c)
+ {
+ return true;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/Variables.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/Variables.java
new file mode 100644
index 000000000..1fc6a8095
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/Variables.java
@@ -0,0 +1,154 @@
+/* Variables.java --
+ Copyright (c) 2004, 2005
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmic;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+class Variables
+{
+ private final HashSet free = new HashSet();
+ private final HashMap names = new HashMap();
+ private final HashSet wides = new HashSet();
+ private final HashSet declared = new HashSet();
+ private boolean allocated = false;
+
+ public void declare(Object name)
+ {
+ declare(name, 1);
+ }
+
+ public void declareWide(Object name)
+ {
+ declare(name, 2);
+ }
+
+ public void declare(Object name, int size)
+ {
+ if (allocated)
+ throw new IllegalStateException("cannot declare after allocating");
+ if (size != 1 && size != 2)
+ throw new IllegalArgumentException("size must be 1 or 2");
+ if (names.containsKey(name))
+ throw new IllegalStateException("already allocated " + name);
+
+ allocateNew(name, size);
+ declared.add(name);
+ }
+
+ private int allocateNew(Object name, int size)
+ {
+ // total allocation size is first unallocated slot
+ int i = free.size() + names.size() + wides.size();
+ names.put(name, new Integer(i));
+ if (size == 2) wides.add(name);
+ return i;
+ }
+
+ public int allocate(Object name)
+ {
+ return allocate(name, 1);
+ }
+
+ public int allocateWide(Object name)
+ {
+ return allocate(name, 2);
+ }
+
+ public int allocate(Object name, int size)
+ {
+ allocated = true;
+ if (size != 1 && size != 2)
+ throw new IllegalArgumentException("size must be 1 or 2");
+ if (names.containsKey(name))
+ throw new IllegalStateException("already allocated " + name);
+
+ if (size == 2)
+ {
+ // look for consecutive free slots
+ for (Iterator it = free.iterator(); it.hasNext(); )
+ {
+ Integer i = (Integer) it.next();
+ Integer next = new Integer(i.intValue() + 1);
+ if (free.contains(next))
+ {
+ free.remove(i);
+ free.remove(next);
+ wides.add(name);
+ names.put(name, i);
+ return i.intValue();
+ }
+ }
+ }
+ else if (free.size() > 0)
+ {
+ Integer i = (Integer) free.iterator().next();
+ free.remove(i);
+ names.put(name, i);
+ return i.intValue();
+ }
+
+ return allocateNew(name, size);
+ }
+
+ public int deallocate(Object name)
+ {
+ if (! names.containsKey(name))
+ throw new IllegalArgumentException("no variable " + name);
+
+ if (declared.contains(name))
+ throw new IllegalStateException(name + " can't be deallocated");
+
+ Integer i = (Integer) names.get(name);
+ names.remove(name);
+ free.add(i);
+ if (wides.remove(name))
+ free.add(new Integer(i.intValue() + 1));
+ return i.intValue();
+ }
+
+ public int get(Object name)
+ {
+ if (! names.containsKey(name))
+ throw new IllegalArgumentException("no variable " + name);
+
+ return ((Integer) names.get(name)).intValue();
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmic/WrapUnWrapper.java b/libjava/classpath/tools/gnu/classpath/tools/rmic/WrapUnWrapper.java
new file mode 100644
index 000000000..cb412851b
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmic/WrapUnWrapper.java
@@ -0,0 +1,99 @@
+/* WrapUnWrapper.java -- Wrapper and unwrapper for primitive types.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmic;
+
+
+public class WrapUnWrapper
+{
+ /**
+ * Get the wrapper class for the primitive type
+ *
+ * @param primitive the class of the primitive type
+ *
+ * @return the wrapper class
+ */
+ public static Class getWrappingClass(Class primitive)
+ {
+ if (primitive.equals(byte.class))
+ return Byte.class;
+ if (primitive.equals(int.class))
+ return Integer.class;
+ if (primitive.equals(long.class))
+ return Long.class;
+ if (primitive.equals(boolean.class))
+ return Boolean.class;
+ if (primitive.equals(double.class))
+ return Double.class;
+ if (primitive.equals(float.class))
+ return Float.class;
+ if (primitive.equals(char.class))
+ return Character.class;
+ else
+ return null;
+ }
+
+ /**
+ * Get the method, invocation of that would return the wrapped value.
+ *
+ * @param primitive the class of the primitive type.
+ *
+ * @return the wrapper method that unwraps the value to the primitive type.
+ */
+ public static String getUnwrappingMethod(Class primitive)
+ {
+ if (primitive.equals(byte.class))
+ return "byteValue()";
+ if (primitive.equals(int.class))
+ return "intValue()";
+ if (primitive.equals(long.class))
+ return "longValue()";
+ if (primitive.equals(boolean.class))
+ return "booleanValue()";
+ if (primitive.equals(double.class))
+ return "doubleValue()";
+ if (primitive.equals(float.class))
+ return "floatValue()";
+ if (primitive.equals(char.class))
+ return "charValue()";
+ else
+ return null;
+ }
+
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java b/libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java
new file mode 100644
index 000000000..fb2764873
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl.java
@@ -0,0 +1,243 @@
+/* ActivationSystemImpl.java -- implementation of the activation system.
+ Copyright (c) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmid;
+
+import gnu.classpath.tools.common.Persistent;
+import gnu.java.rmi.activation.ActivationSystemTransient;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.rmi.activation.ActivationDesc;
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.ActivationGroupDesc;
+import java.rmi.activation.ActivationGroupID;
+import java.rmi.activation.ActivationID;
+import java.rmi.activation.ActivationInstantiator;
+import java.rmi.activation.ActivationMonitor;
+import java.rmi.activation.ActivationSystem;
+import java.rmi.activation.Activator;
+import java.rmi.activation.UnknownGroupException;
+import java.rmi.activation.UnknownObjectException;
+
+/**
+ * Implements the rmid activation system.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+public class ActivationSystemImpl extends ActivationSystemTransient implements
+ ActivationSystem, Activator, ActivationMonitor, Serializable
+{
+ /**
+ * Use for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * The singleton instance of this class.
+ */
+ public static ActivationSystemImpl singleton2;
+
+ /**
+ * Obtain the singleton instance of this class.
+ *
+ * @param folder the folder, where the activation system will keep its files.
+ * @param cold do the cold start if true, hot (usual) if false.
+ */
+ public static ActivationSystem getInstance(File folder, boolean cold)
+ {
+ if (singleton2 == null)
+ singleton2 = new ActivationSystemImpl(folder, cold);
+ return singleton2;
+ }
+
+ /**
+ * Creates the group with transient maps.
+ *
+ * @param folder
+ * the folder, where the activation system will keep its files.
+ * @param cold
+ * do the cold start if true, hot (usual) if false.
+ */
+ protected ActivationSystemImpl(File folder, boolean cold)
+ {
+ super(new PersistentBidiHashTable(), new PersistentBidiHashTable());
+ singleton2 = this;
+ ((PersistentBidiHashTable) groupDescs).init(
+ new File(folder, "asi_objects.data"), cold);
+ ((PersistentBidiHashTable) descriptions).init(
+ new File(folder, "asi_groups.data"), cold);
+ }
+
+ /** @inheritDoc */
+ public MarshalledObject activate(ActivationID id, boolean force)
+ throws ActivationException, UnknownObjectException, RemoteException
+ {
+ return super.activate(id, force);
+ }
+
+ /** @inheritDoc */
+ public ActivationMonitor activeGroup(ActivationGroupID id,
+ ActivationInstantiator group,
+ long incarnation)
+ throws UnknownGroupException, ActivationException, RemoteException
+ {
+ return super.activeGroup(id, group, incarnation);
+ }
+
+ /** @inheritDoc */
+ public void activeObject(ActivationID id, MarshalledObject obj)
+ throws UnknownObjectException, RemoteException
+ {
+ super.activeObject(id, obj);
+ }
+
+ /** @inheritDoc */
+ public ActivationDesc getActivationDesc(ActivationID id)
+ throws ActivationException, UnknownObjectException, RemoteException
+ {
+ return super.getActivationDesc(id);
+ }
+
+ public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID groupId)
+ throws ActivationException, UnknownGroupException, RemoteException
+ {
+ return super.getActivationGroupDesc(groupId);
+ }
+
+ /** @inheritDoc */
+ public void inactiveGroup(ActivationGroupID groupId, long incarnation)
+ throws UnknownGroupException, RemoteException
+ {
+ super.inactiveGroup(groupId, incarnation);
+ }
+
+ /** @inheritDoc */
+ public void inactiveObject(ActivationID id) throws UnknownObjectException,
+ RemoteException
+ {
+ super.inactiveObject(id);
+ }
+
+ /** @inheritDoc */
+ public ActivationGroupID registerGroup(ActivationGroupDesc groupDesc)
+ throws ActivationException, RemoteException
+ {
+ return super.registerGroup(groupDesc);
+ }
+
+ /** @inheritDoc */
+ public ActivationID registerObject(ActivationDesc desc)
+ throws ActivationException, UnknownGroupException, RemoteException
+ {
+ return super.registerObject(desc);
+ }
+
+ /** @inheritDoc */
+ public ActivationDesc setActivationDesc(ActivationID id, ActivationDesc desc)
+ throws ActivationException, UnknownObjectException,
+ UnknownGroupException, RemoteException
+ {
+ return super.setActivationDesc(id, desc);
+ }
+
+ /** @inheritDoc */
+ public ActivationGroupDesc setActivationGroupDesc(
+ ActivationGroupID groupId, ActivationGroupDesc groupDesc)
+ throws ActivationException, UnknownGroupException, RemoteException
+ {
+ return super.setActivationGroupDesc(groupId, groupDesc);
+ }
+
+ /**
+ * This method saves the state of the activation system and then
+ * terminates in 10 seconds.
+ */
+ public void shutdown() throws RemoteException
+ {
+ super.shutdown();
+ System.out.println("Shutdown command received. Will terminate in 10 s");
+ Persistent.timer.schedule(new Persistent.ExitTask(), 10000);
+ }
+
+ /** @inheritDoc */
+ public void unregisterGroup(ActivationGroupID groupId)
+ throws ActivationException, UnknownGroupException, RemoteException
+ {
+ super.unregisterGroup(groupId);
+ }
+
+ /** @inheritDoc */
+ public void unregisterObject(ActivationID id) throws ActivationException,
+ UnknownObjectException, RemoteException
+ {
+ super.unregisterObject(id);
+ }
+
+ /**
+ * Read the object from the input stream.
+ *
+ * @param in the stream to read from
+ *
+ * @throws IOException if thrown by the stream
+ * @throws ClassNotFoundException
+ */
+ private void readObject(ObjectInputStream in) throws IOException,
+ ClassNotFoundException
+ {
+ // Read no fields.
+ }
+
+ /**
+ * Write the object to the output stream.
+ *
+ * @param out the stream to write int
+ * @throws IOException if thrown by the stream
+ * @throws ClassNotFoundException
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException,
+ ClassNotFoundException
+ {
+ // Write no fields.
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl_Stub.java b/libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl_Stub.java
new file mode 100644
index 000000000..446a87fb2
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmid/ActivationSystemImpl_Stub.java
@@ -0,0 +1,556 @@
+/* ActivationSystemImpl.java -- implementation of the activation system.
+ Copyright (c) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmid;
+
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.rmi.activation.ActivationDesc;
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.ActivationGroupDesc;
+import java.rmi.activation.ActivationGroupID;
+import java.rmi.activation.ActivationID;
+import java.rmi.activation.ActivationInstantiator;
+import java.rmi.activation.ActivationMonitor;
+import java.rmi.activation.ActivationSystem;
+import java.rmi.activation.Activator;
+import java.rmi.activation.UnknownGroupException;
+import java.rmi.activation.UnknownObjectException;
+
+import java.lang.reflect.Method;
+import java.rmi.server.RemoteRef;
+import java.rmi.server.RemoteStub;
+import java.rmi.UnexpectedException;
+
+/**
+ * This class delegates its method calls to the remote RMI object, referenced
+ * by {@link RemoteRef}.
+ *
+ * It is normally generated with rmic.
+ */
+public final class ActivationSystemImpl_Stub
+ extends RemoteStub
+ implements ActivationMonitor, Activator, ActivationSystem
+{
+ /**
+ * Use serialVersionUID for interoperability
+ */
+ private static final long serialVersionUID = 2;
+
+ /**
+ * The explaining message for {@ling UnexpectedException}.
+ */
+ private static final String exception_message =
+ "undeclared checked exception";
+
+ /* All remote methods, invoked by this stub: */
+ private static final Method met_setActivationGroupDesc;
+ private static final Method met_inactiveGroup;
+ private static final Method met_unregisterObject;
+ private static final Method met_getActivationDesc;
+ private static final Method met_setActivationDesc;
+ private static final Method met_shutdown;
+ private static final Method met_activate;
+ private static final Method met_activeGroup;
+ private static final Method met_registerGroup;
+ private static final Method met_getActivationGroupDesc;
+ private static final Method met_activeObject;
+ private static final Method met_registerObject;
+ private static final Method met_inactiveObject;
+ private static final Method met_unregisterGroup;
+ private static final Object[] NO_ARGS = new Object[0];
+ static
+ {
+ final Class[] NO_ARGSc = new Class[0];
+ try
+ {
+ met_setActivationGroupDesc =
+ ActivationSystem.class.getMethod("setActivationGroupDesc", new Class[]
+ {
+ ActivationGroupID.class, ActivationGroupDesc.class
+ });
+ met_inactiveGroup =
+ ActivationMonitor.class.getMethod("inactiveGroup", new Class[]
+ {
+ ActivationGroupID.class, long.class
+ });
+ met_unregisterObject =
+ ActivationSystem.class.getMethod("unregisterObject", new Class[]
+ {
+ ActivationID.class
+ });
+ met_getActivationDesc =
+ ActivationSystem.class.getMethod("getActivationDesc", new Class[]
+ {
+ ActivationID.class
+ });
+ met_setActivationDesc =
+ ActivationSystem.class.getMethod("setActivationDesc", new Class[]
+ {
+ ActivationID.class, ActivationDesc.class
+ });
+ met_shutdown =
+ ActivationSystem.class.getMethod("shutdown", NO_ARGSc);
+ met_activate =
+ Activator.class.getMethod("activate", new Class[]
+ {
+ ActivationID.class, boolean.class
+ });
+ met_activeGroup =
+ ActivationSystem.class.getMethod("activeGroup", new Class[]
+ {
+ ActivationGroupID.class, ActivationInstantiator.class, long.class
+ });
+ met_registerGroup =
+ ActivationSystem.class.getMethod("registerGroup", new Class[]
+ {
+ ActivationGroupDesc.class
+ });
+ met_getActivationGroupDesc =
+ ActivationSystem.class.getMethod("getActivationGroupDesc", new Class[]
+ {
+ ActivationGroupID.class
+ });
+ met_activeObject =
+ ActivationMonitor.class.getMethod("activeObject", new Class[]
+ {
+ ActivationID.class, MarshalledObject.class
+ });
+ met_registerObject =
+ ActivationSystem.class.getMethod("registerObject", new Class[]
+ {
+ ActivationDesc.class
+ });
+ met_inactiveObject =
+ ActivationMonitor.class.getMethod("inactiveObject", new Class[]
+ {
+ ActivationID.class
+ });
+ met_unregisterGroup =
+ ActivationSystem.class.getMethod("unregisterGroup", new Class[]
+ {
+ ActivationGroupID.class
+ });
+
+ }
+ catch (NoSuchMethodException nex)
+ {
+ NoSuchMethodError err = new NoSuchMethodError(
+ "ActivationSystemImpl_Stub class initialization failed");
+ err.initCause(nex);
+ throw err;
+ }
+ }
+
+ /**
+ * Create the instance for _ActivationSystemImpl_Stub that forwards method calls to the
+ * remote object.
+ *
+ * @para the reference to the remote object.
+ */
+ public ActivationSystemImpl_Stub(RemoteRef reference)
+ {
+ super(reference);
+ }
+
+ /* Methods */
+ /** @inheritDoc */
+ public ActivationGroupDesc setActivationGroupDesc(ActivationGroupID p0,
+ ActivationGroupDesc p1)
+ throws ActivationException, UnknownGroupException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_setActivationGroupDesc,
+ new Object[] { p0, p1 },
+ 1213918527826541191L);
+ return (ActivationGroupDesc) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void inactiveGroup(ActivationGroupID p0, long p1)
+ throws UnknownGroupException, RemoteException
+ {
+ try
+ {
+ ref.invoke(this, met_inactiveGroup, new Object[] { p0, new Long(p1) },
+ -399287892768650944L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void unregisterObject(ActivationID p0) throws ActivationException,
+ UnknownObjectException, RemoteException
+ {
+ try
+ {
+ ref.invoke(this, met_unregisterObject, new Object[] { p0 },
+ -6843850585331411084L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public ActivationDesc getActivationDesc(ActivationID p0)
+ throws ActivationException, UnknownObjectException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_getActivationDesc,
+ new Object[] { p0 }, 4830055440982622087L);
+ return (ActivationDesc) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public ActivationDesc setActivationDesc(ActivationID p0, ActivationDesc p1)
+ throws ActivationException, UnknownObjectException,
+ UnknownGroupException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_setActivationDesc,
+ new Object[] { p0, p1 },
+ 7128043237057180796L);
+ return (ActivationDesc) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void shutdown() throws RemoteException
+ {
+ try
+ {
+ ref.invoke(this, met_shutdown, NO_ARGS, -7207851917985848402L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public MarshalledObject activate(ActivationID p0, boolean p1)
+ throws ActivationException, UnknownObjectException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_activate,
+ new Object[] { p0, new Boolean(p1) },
+ -8767355154875805558L);
+ return (MarshalledObject) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public ActivationMonitor activeGroup(ActivationGroupID p0,
+ ActivationInstantiator p1, long p2)
+ throws UnknownGroupException, ActivationException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_activeGroup,
+ new Object[] { p0, p1, new Long(p2) },
+ -4575843150759415294L);
+ return (ActivationMonitor) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public ActivationGroupID registerGroup(ActivationGroupDesc p0)
+ throws ActivationException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_registerGroup,
+ new Object[] { p0 }, 6921515268192657754L);
+ return (ActivationGroupID) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID p0)
+ throws ActivationException, UnknownGroupException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_getActivationGroupDesc,
+ new Object[] { p0 }, -8701843806548736528L);
+ return (ActivationGroupDesc) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void activeObject(ActivationID p0, MarshalledObject p1)
+ throws UnknownObjectException, RemoteException
+ {
+ try
+ {
+ ref.invoke(this, met_activeObject, new Object[] { p0, p1 },
+ 2543984342209939736L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public ActivationID registerObject(ActivationDesc p0)
+ throws ActivationException, UnknownGroupException, RemoteException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_registerObject,
+ new Object[] { p0 }, -3006759798994351347L);
+ return (ActivationID) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void inactiveObject(ActivationID p0) throws UnknownObjectException,
+ RemoteException
+ {
+ try
+ {
+ ref.invoke(this, met_inactiveObject, new Object[] { p0 },
+ -4165404120701281807L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void unregisterGroup(ActivationGroupID p0) throws ActivationException,
+ UnknownGroupException, RemoteException
+ {
+ try
+ {
+ ref.invoke(this, met_unregisterGroup, new Object[] { p0 },
+ 3768097077835970701L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmid/Main.java b/libjava/classpath/tools/gnu/classpath/tools/rmid/Main.java
new file mode 100644
index 000000000..3cc2a12ad
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmid/Main.java
@@ -0,0 +1,258 @@
+/* Main.java -- the RMI activation daemon.
+ Copyright (c) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmid;
+
+import gnu.classpath.tools.rmid.ActivationSystemImpl;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.java.rmi.activation.ActivationSystemTransient;
+import gnu.java.rmi.server.UnicastServerRef;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.rmi.Remote;
+import java.rmi.activation.ActivationSystem;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.ObjID;
+import java.rmi.server.RMIServerSocketFactory;
+
+
+/**
+ * The persistent RMI activation daemon.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+public class Main
+{
+ /**
+ * The RMI server socket factory.
+ */
+ static RMIServerSocketFactory ACTIVATION_REGISTY_SOCKET_FACTORY = null;
+
+ /**
+ * The activation registry port.
+ */
+ static int ACTIVATION_REGISTRY_PORT = ActivationSystem.SYSTEM_PORT;
+
+ /**
+ * The activation system name.
+ */
+ static String ACTIVATION_SYSTEM_NAME = "java.rmi.activation.ActivationSystem";
+
+ // Parse parameters:
+ private boolean stop = false;
+ private String directory = ".";
+ private boolean cold = false;
+ private boolean persistent = false;
+
+ private Parser initializeParser()
+ {
+ Parser parser = new ClasspathToolParser("rmiregistry", true); //$NON-NLS-1$
+ parser.setHeader(Messages.getString("Main.Usage")); //$NON-NLS-1$
+
+
+ OptionGroup controlGroup
+ = new OptionGroup(Messages.getString("Main.ControlGroup")); //$NON-NLS-1$
+ controlGroup.add(new Option("port", //$NON-NLS-1$
+ Messages.getString("Main.PortOption"), //$NON-NLS-1$
+ Messages.getString("Main.Port")) //$NON-NLS-1$
+ {
+ public void parsed(String portArgument) throws OptionException
+ {
+ ACTIVATION_REGISTRY_PORT = Integer.parseInt(portArgument);
+ }
+ });
+ controlGroup.add(new Option("restart", //$NON-NLS-1$
+ Messages.getString("Main.Restart")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ cold = true;
+ }
+ });
+ controlGroup.add(new Option("stop", //$NON-NLS-1$
+ Messages.getString("Main.Stop")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ stop = true;
+ }
+ });
+ parser.add(controlGroup);
+
+ OptionGroup persistenceGroup
+ = new OptionGroup(Messages.getString("Main.PersistenceGroup")); //$NON-NLS-1$
+ persistenceGroup.add(new Option("persistent", //$NON-NLS-1$
+ Messages.getString("Main.Persistent")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ persistent = true;
+ }
+ });
+ persistenceGroup.add(new Option("directory", //$NON-NLS-1$
+ Messages.getString("Main.Directory"), //$NON-NLS-1$
+ Messages.getString("Main.DirectoryArgument")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ directory = argument;
+ }
+ });
+ parser.add(persistenceGroup);
+
+ OptionGroup debuggingGroup
+ = new OptionGroup(Messages.getString("Main.DebugGroup")); //$NON-NLS-1$
+ debuggingGroup.add(new Option("verbose", //$NON-NLS-1$
+ Messages.getString ("Main.Verbose")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ActivationSystemTransient.debug = true;
+ }
+ });
+ parser.add(debuggingGroup);
+
+ return parser;
+ }
+
+ private void run(String[] args)
+ {
+ Parser p = initializeParser();
+ p.parse(args);
+
+ try
+ {
+ if (!stop)
+ {
+ // Start the system.
+ File dataDirectory = new File(directory);
+ if (!dataDirectory.exists())
+ dataDirectory.mkdirs();
+ ActivationSystem system;
+
+ if (!persistent)
+ system = ActivationSystemTransient.getInstance();
+ else
+ system = ActivationSystemImpl.getInstance(dataDirectory, cold);
+
+ // We must export with the specific activation id that is only
+ // possible when going into the gnu.java.rmi.activation.
+ UnicastServerRef sref = new UnicastServerRef(
+ new ObjID(ObjID.ACTIVATOR_ID), ACTIVATION_REGISTRY_PORT,
+ ACTIVATION_REGISTY_SOCKET_FACTORY);
+ Remote systemStub = sref.exportObject(system);
+
+ // Start the naming system on the activation system port
+ // (if not already running).
+
+ Registry r;
+ try
+ {
+ // Expect the naming service running first.
+ // The local host may want to use the shared registry
+ r = LocateRegistry.getRegistry(ACTIVATION_REGISTRY_PORT);
+ r.rebind(ACTIVATION_SYSTEM_NAME, systemStub);
+ }
+ catch (Exception ex)
+ {
+ // The naming service is not running. Start it.
+ r = LocateRegistry.createRegistry(ACTIVATION_REGISTRY_PORT);
+ r.rebind(ACTIVATION_SYSTEM_NAME, systemStub);
+ }
+ String host = InetAddress.getLocalHost().getCanonicalHostName();
+ System.out.println("The RMI daemon is listening on " + host +
+ " (port "
+ + ACTIVATION_REGISTRY_PORT + ")");
+
+ }
+ else
+ {
+ // Stop the activation system.
+ Registry r;
+ try
+ {
+ System.out.print("Stopping RMI daemon at "
+ + ACTIVATION_REGISTRY_PORT+" ... ");
+ // Expect the naming service running first.
+ // The local host may want to use the shared registry
+ r = LocateRegistry.getRegistry(ACTIVATION_REGISTRY_PORT);
+ ActivationSystem asys =
+ (ActivationSystem) r.lookup(ACTIVATION_SYSTEM_NAME);
+ asys.shutdown();
+ System.out.println("OK.");
+ }
+ catch (Exception ex)
+ {
+ System.out.println("The RMI daemon seems not running at "
+ + ACTIVATION_REGISTRY_PORT);
+ if (ActivationSystemTransient.debug)
+ ex.printStackTrace();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println("Failed to start the RMI daemon.");
+ if (ActivationSystemTransient.debug)
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * The activation system entry point.
+ */
+ public static void main(String[] args)
+ {
+ Main rmidprogram = new Main();
+ try
+ {
+ rmidprogram.run(args);
+ }
+ catch (Exception e)
+ {
+ System.err.println(Messages.getString("Main.InternalError")); //$NON-NLS-1$
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmid/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/rmid/Messages.java
new file mode 100644
index 000000000..4365c6de7
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmid/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- localization support for rmid
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.rmid;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.rmid.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmid/PersistentBidiHashTable.java b/libjava/classpath/tools/gnu/classpath/tools/rmid/PersistentBidiHashTable.java
new file mode 100644
index 000000000..9d9849663
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmid/PersistentBidiHashTable.java
@@ -0,0 +1,269 @@
+/* PersistentBidiHasthable.java -- Bidirectional persistent hash table.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmid;
+
+import gnu.classpath.tools.common.Persistent;
+import gnu.classpath.tools.rmid.ActivationSystemImpl;
+import gnu.java.rmi.activation.BidiTable;
+
+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.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TimerTask;
+
+/**
+ * The persistent bidirectional hash table, maps both a to b and b to a. The
+ * changes are written to dist after SAVE_AT_MOST_AFTER time from the latest
+ * database change or at most after ALWAYS_UPDATE, if the database is updated
+ * very frequently. To ensure that no information is lost, the shutdown method
+ * must be called before exit.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+public class PersistentBidiHashTable extends BidiTable implements
+ Persistent
+{
+ class WriteToDiskTask extends TimerTask
+ {
+ /**
+ * Save the database.
+ */
+ public void run()
+ {
+ writeContent();
+ sheduled = null;
+ }
+ }
+
+ /**
+ * Replaces instances of ActivationSystemImpl into the currently active
+ * instance of the ActivationSystemImpl
+ */
+ class AdaptedReader extends ObjectInputStream
+ {
+ AdaptedReader(InputStream in) throws IOException
+ {
+ super(in);
+ enableResolveObject(true);
+ }
+
+ protected Object resolveObject(Object obj) throws IOException
+ {
+ if (obj instanceof ActivationSystemImpl)
+ return ActivationSystemImpl.singleton2;
+ else
+ return obj;
+ }
+ }
+
+ /**
+ * The database file.
+ */
+ File database;
+
+ /**
+ * The currently sheduled write to disk task, null if none.
+ */
+ WriteToDiskTask sheduled = null;
+
+ /**
+ * The time, when the disk database was last updated.
+ */
+ long lastUpdated;
+
+ /**
+ * Create the unitialised instance that must be initalised when
+ * ActivationSystemImpl.singleton2 is assigned.
+ */
+ public PersistentBidiHashTable()
+ {
+ // Do not initalise the table fields - the initalise method must be
+ // called later.
+ super(0);
+ }
+
+ /**
+ * Create a new persistent table that stores its information into the given
+ * file. The ActivationSystemImpl.singleton2 must be assigned.
+ *
+ * @param file
+ * the file, where the table stores its information.
+ * @param coldStart
+ * if true, the existing file with this name will be erased and
+ * ignored. Otherwise, it will be assumed that the file contains the
+ * persistent table information.
+ */
+ public void init(File file, boolean coldStart)
+ {
+ try
+ {
+ database = file;
+ if (database.exists())
+ {
+ if (coldStart)
+ {
+ k2v = new Hashtable();
+ v2k = new Hashtable();
+ database.delete();
+ }
+ else
+ {
+ FileInputStream fi = new FileInputStream(file);
+ BufferedInputStream b = new BufferedInputStream(fi);
+ ObjectInputStream oin = new AdaptedReader(b);
+
+ k2v = (Map) oin.readObject();
+ oin.close();
+
+ v2k = new Hashtable(k2v.size());
+
+ // Reguild v2k from k2v:
+ Iterator en = k2v.keySet().iterator();
+ Object key;
+ while (en.hasNext())
+ {
+ key = en.next();
+ v2k.put(k2v.get(key), key);
+ }
+ }
+ }
+ else
+ {
+ k2v = new Hashtable();
+ v2k = new Hashtable();
+ }
+ }
+ catch (Exception ioex)
+ {
+ InternalError ierr = new InternalError("Unable to intialize with file "
+ + file);
+ ierr.initCause(ioex);
+ throw ierr;
+ }
+ }
+
+ /**
+ * Write the database content to the disk.
+ */
+ public synchronized void writeContent()
+ {
+ try
+ {
+ FileOutputStream fou = new FileOutputStream(database);
+ BufferedOutputStream b = new BufferedOutputStream(fou);
+ ObjectOutputStream oout = new ObjectOutputStream(b);
+ oout.writeObject(k2v);
+ oout.close();
+ }
+ catch (Exception ioex)
+ {
+ InternalError ierr = new InternalError(
+ "Failed to write database to disk: "
+ + database);
+ ierr.initCause(ioex);
+ throw ierr;
+ }
+ }
+
+ /**
+ * Mark the modified database as modified. The database will be written after
+ * several seconds, unless another modification occurs.
+ */
+ public void markDirty()
+ {
+ if (System.currentTimeMillis() - lastUpdated > ALWAYS_UPDATE)
+ {
+ // Force storing to disk under intensive operation.
+ writeContent();
+ lastUpdated = System.currentTimeMillis();
+ if (sheduled != null)
+ {
+ sheduled.cancel();
+ sheduled = null;
+ }
+ }
+ else
+ {
+ // Otherwise coalesce the disk database copy update events.
+ if (sheduled != null)
+ sheduled.cancel();
+ sheduled = new WriteToDiskTask();
+ timer.schedule(sheduled, SAVE_AT_MOST_AFTER);
+ }
+ }
+
+ /**
+ * Save the current database state to the disk before exit.
+ */
+ public void shutdown()
+ {
+ if (sheduled != null)
+ {
+ writeContent();
+ sheduled = null;
+ }
+ }
+
+ /**
+ * Update the memory maps and mark as should be written to the disk.
+ */
+ public void put(Object key, Object value)
+ {
+ super.put(key, value);
+ markDirty();
+ }
+
+ /**
+ * Update the memory maps and mark as should be written to the disk.
+ */
+ public void removeKey(Object key)
+ {
+ super.removeKey(key);
+ markDirty();
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Main.java b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Main.java
new file mode 100644
index 000000000..f22e81b6e
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Main.java
@@ -0,0 +1,232 @@
+/* Main.java -- RMI registry starter.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmiregistry;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.OptionGroup;
+import gnu.classpath.tools.getopt.Parser;
+import gnu.classpath.tools.rmiregistry.RegistryImpl;
+import gnu.java.rmi.server.UnicastServerRef;
+
+import java.io.File;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.ObjID;
+import java.rmi.server.RMIServerSocketFactory;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * The optionally persistent RMI registry implementation.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+public class Main
+{
+ /**
+ * The stop command.
+ */
+ public static String STOP = "gnu.classpath.tools.rmi.registry.command.STOP";
+
+ /**
+ * If true, the registry prints registration events to console.
+ */
+ public static boolean verbose = false;
+
+ /**
+ * Parsed parameters.
+ */
+ private String directory = ".";
+ private boolean cold = false;
+ private boolean persistent = false;
+ private boolean stop = false;
+ private int port = Registry.REGISTRY_PORT;
+ private RMIServerSocketFactory ssf = null;
+
+ private Parser initializeParser()
+ {
+ Parser parser = new ClasspathToolParser("rmiregistry", true); //$NON-NLS-1$
+ parser.setHeader(Messages.getString("Main.Usage")); //$NON-NLS-1$
+
+ OptionGroup controlGroup
+ = new OptionGroup(Messages.getString("Main.ControlGroup")); //$NON-NLS-1$
+ controlGroup.add(new Option("restart", //$NON-NLS-1$
+ Messages.getString("Main.Restart")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ cold = true;
+ }
+ });
+ controlGroup.add(new Option("stop", //$NON-NLS-1$
+ Messages.getString("Main.Stop")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ stop = true;
+ }
+ });
+ parser.add(controlGroup);
+
+ OptionGroup persistenceGroup
+ = new OptionGroup(Messages.getString("Main.PersistenceGroup")); //$NON-NLS-1$
+ persistenceGroup.add(new Option("persistent", //$NON-NLS-1$
+ Messages.getString("Main.Persistent")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ persistent = true;
+ }
+ });
+ persistenceGroup.add(new Option("directory", //$NON-NLS-1$
+ Messages.getString("Main.Directory"), //$NON-NLS-1$
+ Messages.getString("Main.DirectoryArgument")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ directory = argument;
+ }
+ });
+ parser.add(persistenceGroup);
+
+ OptionGroup debuggingGroup
+ = new OptionGroup(Messages.getString("Main.DebugGroup")); //$NON-NLS-1$
+ debuggingGroup.add(new Option("verbose", //$NON-NLS-1$
+ Messages.getString ("Main.Verbose")) //$NON-NLS-1$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ parser.add(debuggingGroup);
+
+ return parser;
+ }
+
+ private void run(String[] args)
+ {
+ Parser p = initializeParser();
+ p.parse(args, new FileArgumentCallback()
+ {
+ public void notifyFile(String portArgument)
+ {
+ port = Integer.parseInt(portArgument);
+ }
+ });
+
+ if (!stop)
+ {
+ Map table;
+ if (!persistent)
+ table = new Hashtable();
+ else
+ {
+ // Start the system.
+ File dataDirectory = new File(directory);
+ if (!dataDirectory.exists())
+ dataDirectory.mkdirs();
+ table = PersistentHashTable.createInstance(
+ new File(dataDirectory, "rmiregistry.data"), cold);
+ }
+
+ RegistryImpl system = new RegistryImpl(table);
+
+ // We must export with the specific activation id that is only
+ // possible when going into the gnu.java.rmi
+ try
+ {
+ UnicastServerRef sref = new UnicastServerRef(
+ new ObjID(ObjID.REGISTRY_ID), port, ssf);
+
+ sref.exportObject(system);
+ System.out.println("The RMI naming service is listening at " + port);
+ }
+ catch (Exception ex)
+ {
+ System.out.println("Failed to start RMI naming service at " + port);
+ }
+ }
+ else
+ {
+ // Stop the naming service.
+ try
+ {
+ Registry r = LocateRegistry.getRegistry(port);
+ // Search for this specific line will command to stop the registry.
+
+ // Our service returns null, but any other service will thrown
+ // NotBoundException.
+ r.unbind(STOP);
+ }
+ catch (RemoteException e)
+ {
+ System.out.println("Failed to stop RMI naming service at " + port);
+ }
+ catch (NotBoundException e)
+ {
+ System.out.println("The naming service at port " + port + " is not a "
+ + Main.class.getName());
+ }
+ }
+ }
+
+ /**
+ * The RMI registry implementation entry point.
+ */
+ public static void main(String[] args)
+ {
+ Main rmiregistryprogram = new Main();
+ try
+ {
+ rmiregistryprogram.run(args);
+ }
+ catch (Exception e)
+ {
+ System.err.println(Messages.getString("Main.InternalError")); //$NON-NLS-1$
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Messages.java
new file mode 100644
index 000000000..05bfcf62d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- localization support for rmiregistry
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.rmiregistry;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.rmiregistry.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/PersistentHashTable.java b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/PersistentHashTable.java
new file mode 100644
index 000000000..3202a8405
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/PersistentHashTable.java
@@ -0,0 +1,262 @@
+/* PersistentHasthable.java -- Persistent hash table.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmiregistry;
+
+import gnu.classpath.tools.common.Persistent;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.TimerTask;
+
+/**
+ * The persistent hash table. The changes are written to dist after
+ * SAVE_AT_MOST_AFTER time from the latest database change or at most after
+ * ALWAYS_UPDATE, if the database is updated very frequently. To ensure that no
+ * information is lost, the shutdown method must be called before exit.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+public class PersistentHashTable
+ extends Hashtable
+ implements Serializable, Persistent
+{
+
+ /**
+ * Use serialVersionUID for interoperability
+ */
+ private static final long serialVersionUID = 1;
+
+ class WriteToDiskTask extends TimerTask
+ {
+ /**
+ * Save the database.
+ */
+ public void run()
+ {
+ writeContent();
+ sheduled = null;
+ }
+ }
+
+ /**
+ * The database file.
+ */
+ File database;
+
+ /**
+ * The currently sheduled write to disk task, null if none.
+ */
+ WriteToDiskTask sheduled = null;
+
+ /**
+ * The time, when the disk database was last updated.
+ */
+ long lastUpdated;
+
+ /**
+ * Setting to false prevents the automated disk update.
+ * The initial value is true to prevent writing while reading and is set
+ * to false in createInstance.
+ */
+ transient boolean ready;
+
+ /**
+ * Use static method to obtain the instance.
+ */
+ private PersistentHashTable(File file)
+ {
+ if (file == null)
+ throw new NullPointerException("Null file provided");
+ database = file;
+ }
+
+ /**
+ * Create a new persistent table that stores its information into the given
+ * file.
+ *
+ * @param file
+ * the file, where the table stores its information.
+ * @param coldStart
+ * if true, the existing file with this name will be erased and
+ * ignored. Otherwise, it will be assumed that the file contains the
+ * persistent table information.
+ */
+ public static Map createInstance(File file, boolean coldStart)
+ {
+ try
+ {
+ PersistentHashTable k2v;
+ System.out.println ("Here1");
+ if (file.exists())
+ {
+ System.out.println ("Here2");
+ if (coldStart)
+ {
+ System.out.println ("Here2.5");
+ file.delete();
+ k2v = new PersistentHashTable(file);
+ }
+ else
+ {
+ System.out.println ("Here3");
+ FileInputStream fi = new FileInputStream(file);
+ System.out.println ("Here3.1");
+ BufferedInputStream b = new BufferedInputStream(fi);
+ System.out.println ("Here3.2");
+ ObjectInputStream oin = new ObjectInputStream(b);
+ System.out.println ("Here3.3");
+
+ System.out.println ("Here4");
+ k2v = (PersistentHashTable) oin.readObject();
+ oin.close();
+ System.out.println ("Here5");
+ }
+ }
+ else
+ {
+ System.out.println ("Here6");
+ k2v = new PersistentHashTable(file);
+ System.out.println ("Here7");
+ }
+
+ System.out.println ("Here8");
+ k2v.ready = true;
+ return k2v;
+ }
+ catch (Exception ioex)
+ {
+ InternalError ierr = new InternalError("Unable to intialize with file "
+ + file);
+ ierr.initCause(ioex);
+ throw ierr;
+ }
+ }
+
+
+ /**
+ * Write the database content to the disk.
+ */
+ public synchronized void writeContent()
+ {
+ try
+ {
+ FileOutputStream fou = new FileOutputStream(database);
+ BufferedOutputStream b = new BufferedOutputStream(fou);
+ ObjectOutputStream oout = new ObjectOutputStream(b);
+ oout.writeObject(this);
+ oout.close();
+ }
+ catch (Exception ioex)
+ {
+ InternalError ierr = new InternalError(
+ "Failed to write database to disk: "+ database);
+ ierr.initCause(ioex);
+ throw ierr;
+ }
+ }
+
+ /**
+ * Mark the modified database as modified. The database will be written after
+ * several seconds, unless another modification occurs.
+ */
+ public void markDirty()
+ {
+ if (System.currentTimeMillis() - lastUpdated > ALWAYS_UPDATE)
+ {
+ // Force storing to disk under intensive operation.
+ writeContent();
+ lastUpdated = System.currentTimeMillis();
+ if (sheduled != null)
+ {
+ sheduled.cancel();
+ sheduled = null;
+ }
+ }
+ else
+ {
+ // Otherwise coalesce the disk database copy update events.
+ if (sheduled != null)
+ sheduled.cancel();
+ sheduled = new WriteToDiskTask();
+ timer.schedule(sheduled, SAVE_AT_MOST_AFTER);
+ }
+ }
+
+ /**
+ * Save the current database state to the disk before exit.
+ */
+ public void shutdown()
+ {
+ if (sheduled != null)
+ {
+ writeContent();
+ sheduled = null;
+ }
+ }
+
+ /**
+ * Update the memory maps and mark as should be written to the disk.
+ */
+ public Object put(Object key, Object value)
+ {
+ super.put(key, value);
+ if (ready)
+ markDirty();
+ return value;
+ }
+
+ /**
+ * Update the memory maps and mark as should be written to the disk.
+ */
+ public Object remove(Object key)
+ {
+ Object removed = super.remove(key);
+ if (ready)
+ markDirty();
+ return removed;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl.java b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl.java
new file mode 100644
index 000000000..80d0fe0c1
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl.java
@@ -0,0 +1,138 @@
+/* RegistryImpl.java -- the RMI registry implementation
+ Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 2006
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmiregistry;
+
+import gnu.classpath.tools.common.Persistent;
+
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+import java.util.ArrayList;
+import java.util.Map;
+
+/**
+ * The optionally persistent registry implementation.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+public class RegistryImpl implements Registry
+{
+ /**
+ * The binding table.
+ */
+ Map bindings;
+
+ /**
+ * Create the registry implementation that uses the given bidirectinal
+ * table to keep the data.
+ */
+ public RegistryImpl(Map aTable)
+ {
+ bindings = aTable;
+ }
+
+ /** @inheritDoc */
+ public Remote lookup(String name) throws RemoteException, NotBoundException,
+ AccessException
+ {
+ Object obj = bindings.get(name);
+ if (obj == null)
+ throw new NotBoundException(name);
+ return ((Remote) obj);
+ }
+
+ /** @inheritDoc */
+ public void bind(String name, Remote obj) throws RemoteException,
+ AlreadyBoundException, AccessException
+ {
+ if (Main.verbose)
+ System.out.println("Bind "+name);
+ if (bindings.containsKey(name))
+ throw new AlreadyBoundException(name);
+ bindings.put(name, obj);
+ }
+
+ /** @inheritDoc */
+ public void unbind(String name) throws RemoteException, NotBoundException,
+ AccessException
+ {
+ if (name.equals(Main.STOP))
+ {
+ if (bindings instanceof Persistent)
+ ((Persistent) bindings).writeContent();
+ // Terminate in 10 seconds.
+ System.out.println("Shutdown command received. Will terminate in 10 s");
+ Persistent.timer.schedule(new Persistent.ExitTask(), 10000);
+ }
+ else
+ {
+ if (Main.verbose)
+ System.out.println("Unbind "+name);
+
+ if (!bindings.containsKey(name))
+ throw new NotBoundException(name);
+ else
+ bindings.remove(name);
+ }
+ }
+
+ /** @inheritDoc */
+ public void rebind(String name, Remote obj) throws RemoteException,
+ AccessException
+ {
+ if (Main.verbose)
+ System.out.println("Rebind "+name);
+ bindings.put(name, obj);
+ }
+
+ /** @inheritDoc */
+ public String[] list() throws RemoteException, AccessException
+ {
+ // Create a separated array to prevent race conditions.
+ ArrayList keys = new ArrayList(bindings.keySet());
+ int n = keys.size();
+ String[] rt = new String[n];
+ for (int i = 0; i < n; i++)
+ rt[i] = (String) keys.get(i);
+ return rt;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Skel.java b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Skel.java
new file mode 100644
index 000000000..fa717892a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Skel.java
@@ -0,0 +1,278 @@
+/* RegistryImpl_Skel.java
+ Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.rmiregistry;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.rmi.MarshalException;
+import java.rmi.Remote;
+import java.rmi.UnmarshalException;
+import java.rmi.server.Operation;
+import java.rmi.server.RemoteCall;
+import java.rmi.server.SkeletonMismatchException;
+
+/**
+ * This skeleton supports unlikely cases when the naming service is
+ * contacted from other interoperable java implementation that still uses
+ * the old style skeleton-dependent invocations.
+ */
+public final class RegistryImpl_Skel
+ implements java.rmi.server.Skeleton
+{
+ private static final long interfaceHash = 4905912898345647071L;
+
+ /**
+ * Repeated multiple times.
+ */
+ static final String EUM = "error unmarshalling arguments for Registry";
+
+ /**
+ * Repeated multiple times.
+ */
+ static final String EMR = "error marshalling return from Registry";
+
+ private static final Operation[] operations =
+ {
+ new Operation("void bind(java.lang.String, Remote"),
+ new Operation("java.lang.String[] list("),
+ new Operation("Remote lookup(java.lang.String"),
+ new Operation("void rebind(java.lang.String, Remote"),
+ new Operation("void unbind(java.lang.String")
+ };
+
+ public Operation[] getOperations()
+ {
+ return ((Operation[]) operations.clone());
+ }
+
+ public void dispatch(Remote obj, RemoteCall call,
+ int opnum, long hash) throws java.lang.Exception
+ {
+ if (opnum < 0)
+ {
+ if (hash == 7583982177005850366L)
+ opnum = 0;
+ else if (hash == 2571371476350237748L)
+ opnum = 1;
+ else if (hash == -7538657168040752697L)
+ opnum = 2;
+ else if (hash == -8381844669958460146L)
+ opnum = 3;
+ else if (hash == 7305022919901907578L)
+ opnum = 4;
+ else
+ throw new SkeletonMismatchException("interface hash mismatch");
+ }
+ else if (hash != interfaceHash)
+ throw new SkeletonMismatchException("interface hash mismatch");
+
+ RegistryImpl server = (RegistryImpl) obj;
+ switch (opnum)
+ {
+ case 0:
+ {
+ java.lang.String $param_0;
+ Remote $param_1;
+ try
+ {
+ ObjectInput in = call.getInputStream();
+ $param_0 = (java.lang.String) in.readObject();
+ $param_1 = (Remote) in.readObject();
+
+ }
+ catch (IOException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ catch (java.lang.ClassCastException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ finally
+ {
+ call.releaseInputStream();
+ }
+ server.bind($param_0, $param_1);
+ try
+ {
+ ObjectOutput out = call.getResultStream(true);
+ }
+ catch (IOException e)
+ {
+ throw new MarshalException(EMR, e);
+ }
+ break;
+ }
+
+ case 1:
+ {
+ try
+ {
+ ObjectInput in = call.getInputStream();
+
+ }
+ catch (IOException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ finally
+ {
+ call.releaseInputStream();
+ }
+ java.lang.String[] $result = server.list();
+ try
+ {
+ ObjectOutput out = call.getResultStream(true);
+ out.writeObject($result);
+ }
+ catch (IOException e)
+ {
+ throw new MarshalException(EMR, e);
+ }
+ break;
+ }
+
+ case 2:
+ {
+ java.lang.String $param_0;
+ try
+ {
+ ObjectInput in = call.getInputStream();
+ $param_0 = (java.lang.String) in.readObject();
+
+ }
+ catch (IOException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ catch (java.lang.ClassCastException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ finally
+ {
+ call.releaseInputStream();
+ }
+ Remote $result = server.lookup($param_0);
+ try
+ {
+ ObjectOutput out = call.getResultStream(true);
+ out.writeObject($result);
+ }
+ catch (IOException e)
+ {
+ throw new MarshalException(EMR, e);
+ }
+ break;
+ }
+
+ case 3:
+ {
+ java.lang.String $param_0;
+ Remote $param_1;
+ try
+ {
+ ObjectInput in = call.getInputStream();
+ $param_0 = (java.lang.String) in.readObject();
+ $param_1 = (Remote) in.readObject();
+
+ }
+ catch (IOException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ catch (java.lang.ClassCastException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ finally
+ {
+ call.releaseInputStream();
+ }
+ server.rebind($param_0, $param_1);
+ try
+ {
+ ObjectOutput out = call.getResultStream(true);
+ }
+ catch (IOException e)
+ {
+ throw new MarshalException(EMR, e);
+ }
+ break;
+ }
+
+ case 4:
+ {
+ java.lang.String $param_0;
+ try
+ {
+ ObjectInput in = call.getInputStream();
+ $param_0 = (java.lang.String) in.readObject();
+
+ }
+ catch (IOException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ catch (java.lang.ClassCastException e)
+ {
+ throw new UnmarshalException(EUM, e);
+ }
+ finally
+ {
+ call.releaseInputStream();
+ }
+ server.unbind($param_0);
+ try
+ {
+ ObjectOutput out = call.getResultStream(true);
+ }
+ catch (IOException e)
+ {
+ throw new MarshalException(EMR, e);
+ }
+ break;
+ }
+
+ default:
+ throw new UnmarshalException("invalid method number");
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Stub.java b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Stub.java
new file mode 100644
index 000000000..dfb277fbd
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/rmiregistry/RegistryImpl_Stub.java
@@ -0,0 +1,263 @@
+/* RegistryImpl_Stub.java -- Registry stub.
+ Copyright (c) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.rmiregistry;
+
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+
+import java.lang.reflect.Method;
+import java.rmi.server.RemoteRef;
+import java.rmi.server.RemoteStub;
+import java.rmi.UnexpectedException;
+
+/**
+ * This class delegates its method calls to the remote RMI object, referenced
+ * by {@link RemoteRef}.
+ *
+ * It is normally generated with rmic.
+ */
+public final class RegistryImpl_Stub
+ extends RemoteStub
+ implements Registry
+{
+ /**
+ * Use serialVersionUID for interoperability
+ */
+ private static final long serialVersionUID = 3;
+
+ /**
+ * The explaining message for {@ling UnexpectedException}.
+ */
+ private static final String exception_message =
+ "undeclared checked exception";
+
+ /* All remote methods, invoked by this stub: */
+ private static final Method met_list;
+ private static final Method met_rebind;
+ private static final Method met_unbind;
+ private static final Method met_lookup;
+ private static final Method met_bind;
+ private static final Object[] NO_ARGS = new Object[0];
+ static
+ {
+ final Class[] NO_ARGSc = new Class[0];
+ try
+ {
+ met_list =
+ Registry.class.getMethod("list", NO_ARGSc);
+ met_rebind =
+ Registry.class.getMethod("rebind", new Class[]
+ {
+ String.class, Remote.class
+ });
+ met_unbind =
+ Registry.class.getMethod("unbind", new Class[]
+ {
+ String.class
+ });
+ met_lookup =
+ Registry.class.getMethod("lookup", new Class[]
+ {
+ String.class
+ });
+ met_bind =
+ Registry.class.getMethod("bind", new Class[]
+ {
+ String.class, Remote.class
+ });
+
+ }
+ catch (NoSuchMethodException nex)
+ {
+ NoSuchMethodError err = new NoSuchMethodError(
+ "RegistryImpl_Stub class initialization failed");
+ err.initCause(nex);
+ throw err;
+ }
+ }
+
+ /**
+ * Create the instance for _RegistryImpl_Stub that forwards method calls to the
+ * remote object.
+ *
+ * @para the reference to the remote object.
+ */
+ public RegistryImpl_Stub(RemoteRef reference)
+ {
+ super(reference);
+ }
+
+ /* Methods */
+ /** @inheritDoc */
+ public String [] list()
+ throws RemoteException, AccessException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_list,
+ NO_ARGS,
+ 2571371476350237748L);
+ return (String []) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void rebind(String p0, Remote p1)
+ throws RemoteException, AccessException
+ {
+ try
+ {
+ ref.invoke(this, met_rebind,
+ new Object[] {p0, p1},
+ -8381844669958460146L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void unbind(String p0)
+ throws RemoteException, NotBoundException, AccessException
+ {
+ try
+ {
+ ref.invoke(this, met_unbind,
+ new Object[] {p0},
+ 7305022919901907578L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public Remote lookup(String p0)
+ throws RemoteException, NotBoundException, AccessException
+ {
+ try
+ {
+ Object result = ref.invoke(this, met_lookup,
+ new Object[] {p0},
+ -7538657168040752697L);
+ return (Remote) result;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+ /** @inheritDoc */
+ public void bind(String p0, Remote p1)
+ throws RemoteException, AlreadyBoundException, AccessException
+ {
+ try
+ {
+ ref.invoke(this, met_bind,
+ new Object[] {p0, p1},
+ 7583982177005850366L);
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (RemoteException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ UnexpectedException uex = new UnexpectedException(exception_message);
+ uex.detail = e;
+ throw uex;
+ }
+ }
+
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/serialver/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/serialver/Messages.java
new file mode 100644
index 000000000..a6ab67add
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/serialver/Messages.java
@@ -0,0 +1,68 @@
+/* Messages.java -- translations for serialver tool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.serialver;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.serialver.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ // TODO Auto-generated method stub
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/serialver/SerialVer.java b/libjava/classpath/tools/gnu/classpath/tools/serialver/SerialVer.java
new file mode 100644
index 000000000..5fd7419b2
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/serialver/SerialVer.java
@@ -0,0 +1,179 @@
+/* gnu.classpath.tools.SerialVer
+ Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+package gnu.classpath.tools.serialver;
+
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.File;
+import java.io.ObjectStreamClass;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+/**
+ * This class is an implementation of the `serialver' program. Any number of
+ * class names can be passed as arguments, and the serial version unique
+ * identitfier for each class will be printed in a manner suitable for cuting
+ * and pasting into a Java source file.
+ */
+public class SerialVer
+{
+ // List of classes to load.
+ ArrayList<String> classes = new ArrayList<String>();
+ // The class path to use.
+ String classpath;
+
+ // FIXME: taken from ClassLoader, should share it.
+ private static void addFileURL(ArrayList<URL> list, String file)
+ {
+ try
+ {
+ list.add(new File(file).toURL());
+ }
+ catch(java.net.MalformedURLException x)
+ {
+ }
+ }
+
+ private ClassLoader getClassLoader()
+ {
+ // FIXME: this code is taken from ClassLoader.
+ // We should share it somewhere.
+ URL[] urls;
+ if (classpath == null)
+ urls = new URL[0];
+ else
+ {
+ StringTokenizer tok = new StringTokenizer(classpath,
+ File.pathSeparator, true);
+ ArrayList<URL> list = new ArrayList<URL>();
+ while (tok.hasMoreTokens())
+ {
+ String s = tok.nextToken();
+ if (s.equals(File.pathSeparator))
+ addFileURL(list, "."); //$NON-NLS-1$
+ else
+ {
+ addFileURL(list, s);
+ if (tok.hasMoreTokens())
+ {
+ // Skip the separator.
+ tok.nextToken();
+ // If the classpath ended with a separator,
+ // append the current directory.
+ if (!tok.hasMoreTokens())
+ addFileURL(list, "."); //$NON-NLS-1$
+ }
+ }
+ }
+ urls = new URL[list.size()];
+ urls = (URL[]) list.toArray(urls);
+ }
+ return new URLClassLoader(urls);
+ }
+
+ private void printMessage(String format, String klass)
+ {
+ System.err.println(MessageFormat.format(format, new Object[] { klass }));
+ }
+
+ public void run(String[] args)
+ {
+ Parser p = new ClasspathToolParser("serialver", true) //$NON-NLS-1$
+ {
+ protected void validate() throws OptionException
+ {
+ if (classes.isEmpty())
+ throw new OptionException(Messages.getString("SerialVer.NoClassesSpecd")); //$NON-NLS-1$
+ }
+ };
+ p.setHeader(Messages.getString("SerialVer.HelpHeader")); //$NON-NLS-1$
+
+ p.add(new Option(Messages.getString("SerialVer.5"), Messages.getString("SerialVer.ClasspathHelp"), "PATH") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ if (classpath != null)
+ throw new OptionException(Messages.getString("SerialVer.DupClasspath")); //$NON-NLS-1$
+ classpath = argument;
+ }
+ });
+
+ p.parse(args, new FileArgumentCallback()
+ {
+ public void notifyFile(String fileArgument) throws OptionException
+ {
+ classes.add(fileArgument);
+ }
+ });
+
+ ClassLoader loader = getClassLoader();
+ Iterator it = classes.iterator();
+ while (it.hasNext())
+ {
+ String name = (String) it.next();
+ try
+ {
+ Class clazz = loader.loadClass(name);
+ ObjectStreamClass osc = ObjectStreamClass.lookup(clazz);
+ if (osc != null)
+ System.out.println(clazz.getName() + ": " //$NON-NLS-1$
+ + "static final long serialVersionUID = " //$NON-NLS-1$
+ + osc.getSerialVersionUID() + "L;"); //$NON-NLS-1$
+ else
+ printMessage(Messages.getString("SerialVer.ClassNotSerial"), name); //$NON-NLS-1$
+ }
+ catch (ClassNotFoundException e)
+ {
+ printMessage(Messages.getString("SerialVer.ClassNotFound"), name); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ new SerialVer().run(args);
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/AuthorTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/AuthorTaglet.java
new file mode 100644
index 000000000..1a1f32b7d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/AuthorTaglet.java
@@ -0,0 +1,293 @@
+/* gnu.classpath.tools.taglets.AuthorTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Tag;
+
+/**
+ * The default Taglet which handles Author information.
+ *
+ * @author Julian Scheid (julian@sektor37.de)
+ */
+public class AuthorTaglet implements Taglet {
+
+ /**
+ * Enum class which denotes whether and how to replace email
+ * addresses in author tags.
+ */
+ public static class EmailReplacement {
+ private EmailReplacement() {}
+
+ /**
+ * Specifies that email addresses should not be replaced.
+ */
+ public static final EmailReplacement NO_REPLACEMENT = new EmailReplacement();
+
+ /**
+ * Specifies that author tag text matching "Real Name
+ * (user@domain.tld)" is converted to "&lt;a
+ * href="mailto:user@domain.tld"&gt;Real Name&lt;/a&gt;.
+ */
+ public static final EmailReplacement MAILTO_NAME = new EmailReplacement();
+
+ /**
+ * Specifies that author tag text matching "Real Name
+ * (user@domain.tld)" is converted to "Real Name (&lt;a
+ * href="mailto:user@domain.tld"&gt;user@domain.tld&lt;/a&gt;).
+ */
+ public static final EmailReplacement NAME_MAILTO_ADDRESS = new EmailReplacement();
+
+ /**
+ * Specifies that author tag text matching "Real Name
+ * (user@domain.tld)" is converted to "Real Name (user AT
+ * domain DOT tld)", where the "AT" and "DOT" replacement are
+ * specified by AuthorTaglet.emailAtReplacement and
+ * AuthorTaglet.emailDotReplacement.
+ */
+ public static final EmailReplacement NAME_MANGLED_ADDRESS = new EmailReplacement();
+ }
+
+ private static EmailReplacement emailReplacementType = EmailReplacement.NO_REPLACEMENT;
+ private static String atReplacement = " <b>at</b> ";
+ private static String dotReplacement = " <b>dot</b> ";
+
+ private static final String NAME = "author";
+ private static final String SINGLE_HEADER = "Author:";
+ private static final String MULTI_HEADER = "Authors:";
+
+ private static boolean enabled = true;
+
+ /**
+ * Matches <code>.</code> (dot).
+ */
+ private static final Pattern dotPattern = Pattern.compile("[.]");
+
+ /**
+ * Matches <code>@</code> (at sign).
+ */
+ private static final Pattern atPattern = Pattern.compile("[@]");
+
+ /**
+ * Matches <code>Real Name (user@domain.tld)</code>.
+ */
+ private static final Pattern authorEmailPattern
+ = Pattern.compile("^"
+ + "\\s*" // optional whitespace
+ + "(" // group #1 start (real name)
+ + "(?:[^\t\r\n ]|\\()+" // first name
+ + "(?:\\s+(?:[^\t\r\n ]|\\()+)*" // additional names
+ + ")" // group #1 end
+ + "\\s*" // optional whitespace
+ + "[(<]" // opening paren
+ + "\\s*" // optional whitespace
+ + "(" // group #2 start (email address)
+ + "(" // group #3 start (email user)
+ + "[A-z0-9_\\-\\.]+" // username
+ + ")" // group #3 end
+ + "[@]" // at sign
+ + "[A-z0-9_\\-]+(?:[.][A-z0-9_\\-]+)+[A-z]" // domain
+ + ")" // group #2 end
+ + "\\s*" // optional whitespace
+ + "(?:\\)|>)" // closing paren
+ + "$");
+
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ public static void register(Map tagletMap) {
+ AuthorTaglet authorTaglet = new AuthorTaglet();
+ tagletMap.put(authorTaglet.getName(), authorTaglet);
+ }
+
+ public String toString(Tag tag) {
+ if (enabled) {
+ return toString(new Tag[] { tag });
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String toString(Tag[] tags) {
+ if (!enabled || tags.length == 0) {
+ return null;
+ }
+ else {
+ boolean haveValidTag = false;
+ for (int i = 0; i < tags.length && !haveValidTag; ++i) {
+ if (tags[i].text().length() > 0) {
+ haveValidTag = true;
+ }
+ }
+
+ if (haveValidTag) {
+ StringBuffer result = new StringBuffer();
+ result.append("<dl class=\"tag list\">");
+ result.append("<dt class=\"tag section header\"><b>");
+ if (tags.length == 1) {
+ result.append(SINGLE_HEADER);
+ }
+ else {
+ result.append(MULTI_HEADER);
+ }
+ result.append("</b></dt>");
+ for (int i = 0; i < tags.length; i++) {
+ result.append("<dd class=\"tag item\">");
+ result.append(replaceEmail(tags[i].text()));
+ result.append("</dd>");
+ }
+ result.append("</dl>");
+ return result.toString();
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Reformat the tag text according to {@link #emailReplacementType}.
+ */
+ private String replaceEmail(String text) {
+
+ if (EmailReplacement.NO_REPLACEMENT == emailReplacementType) {
+ return text;
+ }
+ else {
+ Matcher matcher = authorEmailPattern.matcher(text);
+ if (matcher.matches()) {
+ String realName = matcher.group(1);
+ String emailAddress = matcher.group(2);
+ if (EmailReplacement.MAILTO_NAME == emailReplacementType) {
+ return "<a href=\"mailto:" + emailAddress + "\">" + realName + "</a>";
+ }
+ else if (EmailReplacement.NAME_MAILTO_ADDRESS == emailReplacementType) {
+ return realName + " (<a href=\"mailto:" + emailAddress + "\">" + emailAddress + "</a>)";
+ }
+ else if (EmailReplacement.NAME_MANGLED_ADDRESS == emailReplacementType) {
+ Matcher dotMatcher = dotPattern.matcher(emailAddress);
+ Matcher atMatcher = atPattern.matcher(dotMatcher.replaceAll(dotReplacement));
+ String mangledAddress = atMatcher.replaceAll(atReplacement);
+ return realName + " (" + mangledAddress + ")";
+ }
+ else {
+ // this shouldn't happen
+ return text;
+ }
+ }
+ else {
+ return text;
+ }
+ }
+ }
+
+ /**
+ * Set the email replacement type.
+ */
+ public static void setEmailReplacementType(EmailReplacement emailReplacementType)
+ {
+ if (null == emailReplacementType) {
+ throw new NullPointerException();
+ }
+ AuthorTaglet.emailReplacementType = emailReplacementType;
+ }
+
+ /**
+ * Set the HTML text by which the <code>@</code> (at sign) in email
+ * addresses should be replaced if the email replacement type is
+ * <code>NAME_MANGLED_ADDRESS</code>.
+ */
+ public static void setAtReplacement(String atReplacement)
+ {
+ AuthorTaglet.atReplacement = atReplacement;
+ }
+
+ /**
+ * Set the HTML text by which the <code>.</code> (dot) in email
+ * addresses should be replaced if the email replacement type is
+ * <code>NAME_MANGLED_ADDRESS</code>.
+ */
+ public static void setDotReplacement(String dotReplacement)
+ {
+ AuthorTaglet.dotReplacement = dotReplacement;
+ }
+
+ /**
+ * Enables/disables this taglet.
+ */
+ public static void setTagletEnabled(boolean enabled)
+ {
+ AuthorTaglet.enabled = enabled;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/CodeTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/CodeTaglet.java
new file mode 100644
index 000000000..adc34f391
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/CodeTaglet.java
@@ -0,0 +1,101 @@
+/* gnu.classpath.tools.taglets.CodeTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Doc;
+import com.sun.javadoc.Tag;
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.MemberDoc;
+import com.sun.javadoc.SeeTag;
+
+/**
+ * The default Taglet which shows its contents enclosed in a
+ * <code>code</code> tag.
+ *
+ * @author Julian Scheid (julian@sektor37.de)
+ */
+public class CodeTaglet
+ implements Taglet
+{
+ private static final String NAME = "code";
+
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return true;
+ }
+
+ public String toString(Tag tag) {
+ return "<code>" + tag.text() + "</code>";
+ }
+
+ public String toString(Tag[] tag) {
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/CopyrightTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/CopyrightTaglet.java
new file mode 100644
index 000000000..60e3e40a8
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/CopyrightTaglet.java
@@ -0,0 +1,123 @@
+/* gnu.classpath.tools.taglets.CopyrightTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Tag;
+
+/**
+ * A simple Taglet which handles Copyright information.
+ */
+public class CopyrightTaglet implements Taglet {
+
+ private static final String NAME = "copyright";
+ private static final String HEADER = "Copyright:";
+
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ public static void register(Map tagletMap) {
+ CopyrightTaglet copyrightTaglet = new CopyrightTaglet();
+ tagletMap.put(copyrightTaglet.getName(), copyrightTaglet);
+ }
+
+ public String toString(Tag tag) {
+ return toString(new Tag[] { tag });
+ }
+
+ public String toString(Tag[] tags) {
+ if (tags.length == 0) {
+ return null;
+ }
+ else {
+ boolean haveValidTag = false;
+ for (int i = 0; i < tags.length && !haveValidTag; ++i) {
+ if (tags[i].text().length() > 0) {
+ haveValidTag = true;
+ }
+ }
+
+ if (haveValidTag) {
+ StringBuffer result = new StringBuffer();
+ result.append("<dl>");
+ for (int i = 0; i < tags.length; i++) {
+ if (tags[i].text().length() > 0) {
+ result.append("<dt><i>Copyright &#169; " + tags[i].text() + "</i></dt>");
+ }
+ }
+ result.append("</dl>");
+ return result.toString();
+ }
+ else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/DeprecatedTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/DeprecatedTaglet.java
new file mode 100644
index 000000000..d292c7f3a
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/DeprecatedTaglet.java
@@ -0,0 +1,132 @@
+/* gnu.classpath.tools.taglets.DeprecatedTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Tag;
+
+/**
+ * The default Taglet which handles deprecated information.
+ *
+ * @author Julian Scheid (julian@sektor37.de)
+ */
+public class DeprecatedTaglet implements Taglet {
+
+ private static final String NAME = "deprecated";
+ private static final String HEADER = "Deprecated:";
+
+ private static boolean enabled = true;
+
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ public static void register(Map tagletMap) {
+ DeprecatedTaglet deprecatedTaglet = new DeprecatedTaglet();
+ tagletMap.put(deprecatedTaglet.getName(), deprecatedTaglet);
+ }
+
+ public String toString(Tag tag) {
+ if (enabled) {
+ return toString(new Tag[] { tag });
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String toString(Tag[] tags) {
+ if (!enabled || tags.length == 0) {
+ return null;
+ }
+ else {
+
+ StringBuffer result = new StringBuffer();
+ result.append("<div class=\"classdoc-tag-section-header\">");
+ result.append(HEADER);
+ result.append("</div>");
+ result.append("<dl class=\"classdoc-list\">");
+ for (int i = 0; i < tags.length; i++) {
+ result.append("<dt>");
+ result.append(tags[i].text());
+ result.append("</dt>");
+ }
+ result.append("</dl>");
+ return result.toString();
+ }
+ }
+
+ /**
+ * Enables/disables this taglet.
+ */
+ public static void setTagletEnabled(boolean enabled)
+ {
+ DeprecatedTaglet.enabled = enabled;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/GenericTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/GenericTaglet.java
new file mode 100644
index 000000000..31ff28922
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/GenericTaglet.java
@@ -0,0 +1,157 @@
+/* gnu.classpath.tools.taglets.GenericTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Tag;
+
+/**
+ * A taglet which can be configured at runtime.
+ *
+ * @author Julian Scheid (julian@sektor37.de)
+ */
+public class GenericTaglet implements Taglet {
+
+ private String name = "since";
+ private String header = "Since:";
+
+ private boolean scopeOverview;
+ private boolean scopePackage;
+ private boolean scopeType;
+ private boolean scopeConstructor;
+ private boolean scopeMethod;
+ private boolean scopeField;
+
+ private boolean enabled = true;
+
+ public GenericTaglet(String name,
+ String header,
+ boolean scopeOverview,
+ boolean scopePackage,
+ boolean scopeType,
+ boolean scopeConstructor,
+ boolean scopeMethod,
+ boolean scopeField)
+ {
+ this.name = name;
+ this.header = header;
+ this.scopeOverview = scopeOverview;
+ this.scopePackage = scopePackage;
+ this.scopeType = scopeType;
+ this.scopeConstructor = scopeConstructor;
+ this.scopeMethod = scopeMethod;
+ this.scopeField = scopeField;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean inField() {
+ return scopeField;
+ }
+
+ public boolean inConstructor() {
+ return scopeConstructor;
+ }
+
+ public boolean inMethod() {
+ return scopeMethod;
+ }
+
+ public boolean inOverview() {
+ return scopeOverview;
+ }
+
+ public boolean inPackage() {
+ return scopePackage;
+ }
+
+ public boolean inType() {
+ return scopeType;
+ }
+
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ public void register(Map tagletMap) {
+ tagletMap.put(getName(), this);
+ }
+
+ public String toString(Tag tag) {
+ if (enabled) {
+ return toString(new Tag[] { tag });
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String toString(Tag[] tags) {
+ if (!enabled || tags.length == 0) {
+ return null;
+ }
+ else {
+
+ StringBuffer result = new StringBuffer();
+ result.append("<div class=\"classdoc-tag-section-header\">");
+ result.append(header);
+ result.append("</div>");
+ result.append("<dl class=\"classdoc-list\">");
+ for (int i = 0; i < tags.length; i++) {
+ result.append("<dt>");
+ result.append(tags[i].text());
+ result.append("</dt>");
+ }
+ result.append("</dl>");
+ return result.toString();
+ }
+ }
+
+ /**
+ * Enables/disables this taglet.
+ */
+ public void setTagletEnabled(boolean enabled)
+ {
+ this.enabled = enabled;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/GnuExtendedTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/GnuExtendedTaglet.java
new file mode 100644
index 000000000..e78019067
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/GnuExtendedTaglet.java
@@ -0,0 +1,48 @@
+/* gnu.classpath.tools.taglets.GnuExtendedTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import com.sun.javadoc.Tag;
+import com.sun.tools.doclets.Taglet;
+
+public interface GnuExtendedTaglet
+ extends Taglet
+{
+ public String toString(Tag tag, TagletContext context);
+ public String toString(Tag[] tags, TagletContext context);
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/SinceTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/SinceTaglet.java
new file mode 100644
index 000000000..c3737522d
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/SinceTaglet.java
@@ -0,0 +1,161 @@
+/* gnu.classpath.tools.taglets.SinceTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Tag;
+
+import gnu.classpath.tools.doclets.InlineTagRenderer;
+
+/**
+ * The default Taglet which handles since information.
+ *
+ * @author Julian Scheid (julian@sektor37.de)
+ */
+public class SinceTaglet implements GnuExtendedTaglet {
+
+ private static final String NAME = "since";
+ private static final String HEADER = "Since:";
+
+ private static boolean enabled = true;
+
+ private InlineTagRenderer inlineTagRenderer;
+
+ public SinceTaglet(InlineTagRenderer inlineTagRenderer)
+ {
+ this.inlineTagRenderer = inlineTagRenderer;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ public String toString(Tag tag) {
+ // should raise assertion
+ if (enabled) {
+ return toString(new Tag[] { tag });
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String toString(Tag[] tags) {
+ // should raise assertion
+ return toString(tags, null);
+ }
+
+ public String toString(Tag tag, TagletContext context)
+ {
+ return null;
+ }
+
+ public String toString(Tag[] tags, TagletContext context)
+ {
+ if (!enabled || tags.length == 0) {
+ return null;
+ }
+ else {
+ boolean haveValidTag = false;
+ for (int i = 0; i < tags.length && !haveValidTag; ++i) {
+ if (tags[i].text().length() > 0) {
+ haveValidTag = true;
+ }
+ }
+
+ if (haveValidTag) {
+ StringBuffer result = new StringBuffer();
+ result.append("<dl class=\"tag list\">");
+ result.append("<dt class=\"tag section header\"><b>");
+ result.append(HEADER);
+ result.append("</b></dt>");
+ for (int i = 0; i < tags.length; ++i) {
+ if (tags[i].text().length() > 0) {
+ result.append("<dd>");
+ result.append(inlineTagRenderer.renderInlineTags(tags[i].inlineTags(), context));
+ result.append("</dd>");
+ }
+ }
+ result.append("</dl>");
+ return result.toString();
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Enables/disables this taglet.
+ */
+ public static void setTagletEnabled(boolean enabled)
+ {
+ SinceTaglet.enabled = enabled;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/TagletContext.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/TagletContext.java
new file mode 100644
index 000000000..82d8aea26
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/TagletContext.java
@@ -0,0 +1,60 @@
+/* TagletContext.java -
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import com.sun.javadoc.Doc;
+
+public class TagletContext
+{
+ protected Doc doc;
+
+ public TagletContext(Doc doc)
+ {
+ this.doc = doc;
+ }
+
+ public Doc getDoc()
+ {
+ return this.doc;
+ }
+
+ public String toString()
+ {
+ return "TagletContext{doc=" + doc + "}";
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/ValueTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/ValueTaglet.java
new file mode 100644
index 000000000..1b07ada8c
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/ValueTaglet.java
@@ -0,0 +1,130 @@
+/* gnu.classpath.tools.taglets.ValueTaglet
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Doc;
+import com.sun.javadoc.Tag;
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.MemberDoc;
+import com.sun.javadoc.SeeTag;
+
+/**
+ * The default Taglet which shows final static field values.
+ *
+ * @author Julian Scheid (julian@sektor37.de)
+ */
+public class ValueTaglet
+ implements GnuExtendedTaglet
+{
+ private static final String NAME = "value";
+
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return true;
+ }
+
+ public static void register(Map tagletMap) {
+ ValueTaglet valueTaglet = new ValueTaglet();
+ tagletMap.put(valueTaglet.getName(), valueTaglet);
+ }
+
+ public String toString(Tag tag) {
+ return null;
+ }
+
+ public String toString(Tag tag, TagletContext context) {
+ if (0 == tag.inlineTags().length) {
+ if (context.getDoc().isField()) {
+ FieldDoc fieldDoc = (FieldDoc)context.getDoc();
+ if (fieldDoc.isStatic() && fieldDoc.isFinal()) {
+ return fieldDoc.constantValueExpression();
+ }
+ }
+ }
+ else {
+ MemberDoc referencedMember = ((SeeTag)tag).referencedMember();
+ if (null != referencedMember && referencedMember.isField()) {
+ FieldDoc fieldDoc = (FieldDoc)referencedMember;
+ if (fieldDoc.isStatic() && fieldDoc.isFinal()) {
+ return fieldDoc.constantValueExpression();
+ }
+ }
+ }
+ return "";
+ }
+
+ public String toString(Tag[] tags) {
+ return null;
+ }
+
+ public String toString(Tag[] tags, TagletContext context) {
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/taglets/VersionTaglet.java b/libjava/classpath/tools/gnu/classpath/tools/taglets/VersionTaglet.java
new file mode 100644
index 000000000..fed926e06
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/taglets/VersionTaglet.java
@@ -0,0 +1,153 @@
+/* gnu.classpath.tools.taglets.VersionTaglet
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.taglets;
+
+import java.util.Map;
+
+import com.sun.tools.doclets.Taglet;
+
+import com.sun.javadoc.Tag;
+
+/**
+ * The default Taglet which handles version information.
+ *
+ * @author Julian Scheid (julian@sektor37.de)
+ */
+public class VersionTaglet implements Taglet {
+
+ private static final String NAME = "version";
+ private static final String HEADER = "Version:";
+
+ private static boolean enabled = true;
+
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean inField() {
+ return true;
+ }
+
+ public boolean inConstructor() {
+ return true;
+ }
+
+ public boolean inMethod() {
+ return true;
+ }
+
+ public boolean inOverview() {
+ return true;
+ }
+
+ public boolean inPackage() {
+ return true;
+ }
+
+ public boolean inType() {
+ return true;
+ }
+
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ public static void register(Map tagletMap) {
+ VersionTaglet versionTaglet = new VersionTaglet();
+ tagletMap.put(versionTaglet.getName(), versionTaglet);
+ }
+
+ public String toString(Tag tag) {
+ if (enabled) {
+ return toString(new Tag[] { tag });
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String toString(Tag[] tags) {
+ if (!enabled || tags.length == 0) {
+ return null;
+ }
+ else {
+ boolean haveValidTag = false;
+ for (int i = 0; i < tags.length && !haveValidTag; ++i) {
+ if (tags[i].text().length() > 0) {
+ haveValidTag = true;
+ }
+ }
+
+ if (haveValidTag) {
+
+ StringBuffer result = new StringBuffer();
+ result.append("<dl class=\"tag list\">");
+ result.append("</dl>");
+ result.append("<dt class=\"tag section header\"><b>");
+ result.append(HEADER);
+ result.append("</b></dt><dd>");
+ boolean firstEntry = true;
+ for (int i = 0; i < tags.length; i++) {
+ if (tags[i].text().length() > 0) {
+ if (!firstEntry) {
+ result.append(", ");
+ }
+ else {
+ firstEntry = false;
+ }
+ result.append(tags[i].text());
+ }
+ }
+ result.append("</dd>");
+ result.append("</dl>");
+ return result.toString();
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Enables/disables this taglet.
+ */
+ public static void setTagletEnabled(boolean enabled)
+ {
+ VersionTaglet.enabled = enabled;
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/tnameserv/Main.java b/libjava/classpath/tools/gnu/classpath/tools/tnameserv/Main.java
new file mode 100644
index 000000000..b163fd539
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/tnameserv/Main.java
@@ -0,0 +1,115 @@
+/* Main.java -- Transient GIOP naming service.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath.tools.tnameserv;
+
+import gnu.CORBA.NamingService.NamingServiceTransient;
+import gnu.classpath.tools.common.ClasspathToolParser;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+/**
+ * The implementation of the transient naming service. The naming service
+ * is a kind of the network server that registers local and remote objects
+ * by name, and later can provide the object reference in response to the
+ * given name.
+ *
+ * GNU Classpath currently works with this naming service and is also
+ * interoperable with the Sun Microsystems naming services from releases 1.3 and
+ * 1.4, both transient <i>tnameserv</i> and persistent <i>orbd</i>.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class Main
+{
+ private int port = -1;
+ private String iorf;
+
+ private Parser initializeParser()
+ {
+ Parser parser = new ClasspathToolParser("tnameserv", true); //$NON-NLS-1$
+ parser.setHeader(Messages.getString("Main.Usage")); //$NON-NLS-1$
+
+ parser.add(new Option("ORBInitialPort", //$NON-NLS-1$
+ Messages.getString("Main.ORBInitialPort"), //$NON-NLS-1$
+ Messages.getString("Main.Port")) //$NON-NLS-1$
+ {
+ public void parsed(String portArgument) throws OptionException
+ {
+ port = Integer.parseInt(portArgument);
+ }
+ });
+
+ parser.add(new Option("ior", //$NON-NLS-1$
+ Messages.getString("Main.IOR"), //$NON-NLS-1$
+ Messages.getString("Main.IORFile")) //$NON-NLS-1$
+ {
+ public void parsed(String fileArgument) throws OptionException
+ {
+ iorf = fileArgument;
+ }
+ });
+
+ return parser;
+ }
+
+ private void run(String[] args)
+ {
+ Parser p = initializeParser();
+ p.parse(args);
+ NamingServiceTransient.start(port, iorf);
+ }
+
+ /**
+ * The naming service entry point.
+ */
+ public static void main(String[] args)
+ {
+ Main tnameservprogram = new Main();
+ try
+ {
+ tnameservprogram.run(args);
+ }
+ catch (Exception e)
+ {
+ System.err.println(Messages.getString("Main.InternalError")); //$NON-NLS-1$
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+}
diff --git a/libjava/classpath/tools/gnu/classpath/tools/tnameserv/Messages.java b/libjava/classpath/tools/gnu/classpath/tools/tnameserv/Messages.java
new file mode 100644
index 000000000..505397302
--- /dev/null
+++ b/libjava/classpath/tools/gnu/classpath/tools/tnameserv/Messages.java
@@ -0,0 +1,67 @@
+/* Messages.java -- localization support for tnameserv
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.tnameserv;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages
+{
+ private static final String BUNDLE_NAME
+ = "gnu.classpath.tools.tnameserv.messages"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private Messages()
+ {
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ }
+}