summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorGuilhem Lavaux <guilhem@kaffe.org>2006-06-06 20:30:07 +0000
committerGuilhem Lavaux <guilhem@kaffe.org>2006-06-06 20:30:07 +0000
commit56c5b96a2d3754736d13eebb73270fb8f925301d (patch)
tree8f13d21d9dadf9810d11284977ed98a0a5c41868 /tools
parent68d82e8b935385c52f40123538e6e5b0dad7dbc9 (diff)
downloadclasspath-56c5b96a2d3754736d13eebb73270fb8f925301d.tar.gz
2006-06-06 Guilhem Lavaux <guilhem@kaffe.org>
* Merged HEAD as of 2006-05-08.
Diffstat (limited to 'tools')
-rw-r--r--tools/.cvsignore2
-rwxr-xr-xtools/Makefile.am27
-rw-r--r--tools/README18
-rw-r--r--tools/appletviewer.c235
-rw-r--r--tools/appletviewer.in63
-rw-r--r--tools/gnu/classpath/tools/HelpPrinter.java41
-rw-r--r--tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java81
-rw-r--r--tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java95
-rw-r--r--tools/gnu/classpath/tools/appletviewer/AppletTag.java485
-rw-r--r--tools/gnu/classpath/tools/appletviewer/AppletWarning.java66
-rw-r--r--tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java133
-rw-r--r--tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java138
-rw-r--r--tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java175
-rw-r--r--tools/gnu/classpath/tools/appletviewer/ErrorApplet.java53
-rw-r--r--tools/gnu/classpath/tools/appletviewer/Main.java303
-rw-r--r--tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java72
-rw-r--r--tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java172
-rw-r--r--tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java454
-rw-r--r--tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java75
-rw-r--r--tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java144
-rw-r--r--tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java559
-rw-r--r--tools/gnu/classpath/tools/appletviewer/TagParser.java302
-rw-r--r--tools/gnu/classpath/tools/common/CallbackUtil.java145
-rw-r--r--tools/gnu/classpath/tools/common/ProviderUtil.java163
-rw-r--r--tools/gnu/classpath/tools/common/SecurityProviderInfo.java99
-rw-r--r--tools/gnu/classpath/tools/getopt/ClasspathToolParser.java71
-rw-r--r--tools/gnu/classpath/tools/getopt/FileArgumentCallback.java61
-rw-r--r--tools/gnu/classpath/tools/getopt/Option.java201
-rw-r--r--tools/gnu/classpath/tools/getopt/OptionException.java52
-rw-r--r--tools/gnu/classpath/tools/getopt/OptionGroup.java171
-rw-r--r--tools/gnu/classpath/tools/getopt/Parser.java314
-rw-r--r--tools/gnu/classpath/tools/giop/GRMIC.java22
-rw-r--r--tools/gnu/classpath/tools/giop/GRMIC.txt3
-rw-r--r--tools/gnu/classpath/tools/giop/IorParser.java18
-rw-r--r--tools/gnu/classpath/tools/giop/grmic/CompilationError.java18
-rw-r--r--tools/gnu/classpath/tools/giop/grmic/Generator.java18
-rw-r--r--tools/gnu/classpath/tools/giop/grmic/GiopIo.java18
-rw-r--r--tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java33
-rw-r--r--tools/gnu/classpath/tools/giop/grmic/HashFinder.java22
-rw-r--r--tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java18
-rw-r--r--tools/gnu/classpath/tools/jar/Action.java50
-rw-r--r--tools/gnu/classpath/tools/jar/Creator.java192
-rw-r--r--tools/gnu/classpath/tools/jar/Entry.java60
-rw-r--r--tools/gnu/classpath/tools/jar/Extractor.java100
-rw-r--r--tools/gnu/classpath/tools/jar/Lister.java84
-rw-r--r--tools/gnu/classpath/tools/jar/Main.java225
-rw-r--r--tools/gnu/classpath/tools/jar/Updater.java81
-rw-r--r--tools/gnu/classpath/tools/jarsigner/HashUtils.java122
-rw-r--r--tools/gnu/classpath/tools/jarsigner/JarSigner.java167
-rw-r--r--tools/gnu/classpath/tools/jarsigner/JarVerifier.java339
-rw-r--r--tools/gnu/classpath/tools/jarsigner/Main.java567
-rw-r--r--tools/gnu/classpath/tools/jarsigner/Messages.java115
-rw-r--r--tools/gnu/classpath/tools/jarsigner/SFHelper.java373
-rw-r--r--tools/gnu/classpath/tools/jarsigner/jarsigner.txt116
-rw-r--r--tools/gnu/classpath/tools/jarsigner/package.html60
-rw-r--r--tools/gnu/classpath/tools/keytool/CertReqCmd.java405
-rw-r--r--tools/gnu/classpath/tools/keytool/Command.java1147
-rw-r--r--tools/gnu/classpath/tools/keytool/DeleteCmd.java235
-rw-r--r--tools/gnu/classpath/tools/keytool/ExportCmd.java266
-rw-r--r--tools/gnu/classpath/tools/keytool/GenKeyCmd.java511
-rw-r--r--tools/gnu/classpath/tools/keytool/IdentityDBCmd.java185
-rw-r--r--tools/gnu/classpath/tools/keytool/ImportCmd.java751
-rw-r--r--tools/gnu/classpath/tools/keytool/KeyCloneCmd.java344
-rw-r--r--tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java339
-rw-r--r--tools/gnu/classpath/tools/keytool/ListCmd.java380
-rw-r--r--tools/gnu/classpath/tools/keytool/Main.java219
-rw-r--r--tools/gnu/classpath/tools/keytool/Messages.java115
-rw-r--r--tools/gnu/classpath/tools/keytool/PrintCertCmd.java123
-rw-r--r--tools/gnu/classpath/tools/keytool/SelfCertCmd.java371
-rw-r--r--tools/gnu/classpath/tools/keytool/StorePasswdCmd.java275
-rw-r--r--tools/gnu/classpath/tools/keytool/keytool.txt616
-rw-r--r--tools/gnu/classpath/tools/keytool/package.html65
-rw-r--r--tools/gnu/classpath/tools/rmi/Persistent.java87
-rw-r--r--tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java268
-rw-r--r--tools/gnu/classpath/tools/rmi/PersistentHashTable.java246
-rw-r--r--tools/gnu/classpath/tools/rmi/REGISTRY.java165
-rw-r--r--tools/gnu/classpath/tools/rmi/REGISTRY.txt28
-rw-r--r--tools/gnu/classpath/tools/rmi/RMIC.java23
-rw-r--r--tools/gnu/classpath/tools/rmi/RMIC.txt2
-rw-r--r--tools/gnu/classpath/tools/rmi/RMID.java189
-rw-r--r--tools/gnu/classpath/tools/rmi/RMID.txt30
-rw-r--r--tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java139
-rw-r--r--tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Skel.java278
-rw-r--r--tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Stub.java263
-rw-r--r--tools/gnu/classpath/tools/rmi/registry/package.html46
-rw-r--r--tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java14
-rw-r--r--tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java13
-rw-r--r--tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java19
-rw-r--r--tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav2
-rw-r--r--tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav2
-rw-r--r--tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java244
-rw-r--r--tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl_Stub.java556
-rw-r--r--tools/jarsigner.in63
-rw-r--r--tools/keytool.in63
94 files changed, 16673 insertions, 205 deletions
diff --git a/tools/.cvsignore b/tools/.cvsignore
index eaae7d326..75730de04 100644
--- a/tools/.cvsignore
+++ b/tools/.cvsignore
@@ -1,3 +1,5 @@
+jarsigner
+keytool
Makefile.in
Makefile
tools.zip
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 65858f52a..7a8f1ce97 100755
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,17 +1,19 @@
## Input file for automake to generate the Makefile.in used by configure
+GLIBJ_CLASSPATH='$(top_builddir)/lib':'$(top_builddir)/lib/glibj.zip'
+
# Setup the compiler to use the GNU Classpath library we just build
if FOUND_GCJ
-JCOMPILER = $(GCJ) --bootclasspath '$(top_builddir)/lib' --classpath . -C
+JCOMPILER = $(GCJ) -encoding UTF-8 --bootclasspath $(GLIBJ_CLASSPATH) --classpath . -C
else
if FOUND_JIKES
-JCOMPILER = $(JIKES) -bootclasspath '' -extdirs '' -sourcepath '' --classpath $(top_builddir)/lib:.
+JCOMPILER = $(JIKES) $(JIKESENCODING) -bootclasspath '' -extdirs '' -sourcepath '' --classpath $(GLIBJ_CLASSPATH):.
else
if FOUND_GCJX
-JCOMPILER = $(GCJX) -bootclasspath '' -sourcepath '' -classpath $(top_builddir)/lib:.
+JCOMPILER = $(GCJX) -encoding UTF-8 -bootclasspath '' -sourcepath '' -classpath $(GLIBJ_CLASSPATH):.
else
if FOUND_ECJ
-JCOMPILER = $(ECJ) -bootclasspath '$(top_builddir)/lib' -classpath .
+JCOMPILER = $(ECJ) -encoding UTF-8 -bootclasspath $(GLIBJ_CLASSPATH) -classpath .
else
error dunno how to setup the JCOMPILER and compile
endif
@@ -19,6 +21,9 @@ endif
endif
endif
+bin_SCRIPTS = jarsigner keytool
+EXTRA_DIST = jarsigner.in keytool.in
+
# All our example java source files
TOOLS_JAVA_FILES = $(srcdir)/gnu/classpath/tools/*.java $(srcdir)/gnu/classpath/tools/*/*.java $(srcdir)/gnu/classpath/tools/*/*/*.java
@@ -30,7 +35,7 @@ TOOLS_ZIP = tools.zip
BUILT_SOURCES = $(TOOLS_ZIP)
# The templates that must be included into the generated zip file.
-GRMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/giop/grmic/templates/*.jav
+GRMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/giop/grmic/templates/*.jav
RMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/rmi/rmic/templates/*.jav
TOOLS_TEMPLATES = $(GRMIC_TEMPLATES) $(RMIC_TEMPLATES)
@@ -38,8 +43,10 @@ TOOLS_TEMPLATES = $(GRMIC_TEMPLATES) $(RMIC_TEMPLATES)
# This covers the built-in help texts, both for giop and rmic subpackages.
GIOP_HELPS = $(srcdir)/gnu/classpath/tools/giop/*.txt
RMI_HELPS = $(srcdir)/gnu/classpath/tools/rmi/*.txt
+JARSIGNER_HELPS = $(srcdir)/gnu/classpath/tools/jarsigner/*.txt
+KEYTOOL_HELPS = $(srcdir)/gnu/classpath/tools/keytool/*.txt
-TOOLS_HELPS = $(GIOP_HELPS) $(RMI_HELPS)
+TOOLS_HELPS = $(GIOP_HELPS) $(RMI_HELPS) $(JARSIGNER_HELPS) $(KEYTOOL_HELPS)
# The tool specific README files.
READMES = $(srcdir)/gnu/classpath/tools/giop/README
@@ -74,11 +81,15 @@ dist-hook:
$(TOOLS_ZIP): $(TOOLS_JAVA_FILES)
mkdir -p classes/gnu/classpath/tools/giop/grmic/templates
mkdir -p classes/gnu/classpath/tools/rmi/rmic/templates
+ mkdir -p classes/gnu/classpath/tools/jarsigner
+ mkdir -p classes/gnu/classpath/tools/keytool
cp $(RMIC_TEMPLATES) classes/gnu/classpath/tools/rmi/rmic/templates
- cp $(GRMIC_TEMPLATES) classes/gnu/classpath/tools/giop/grmic/templates
+ cp $(GRMIC_TEMPLATES) classes/gnu/classpath/tools/giop/grmic/templates
cp $(RMI_HELPS) classes/gnu/classpath/tools/rmi/
cp $(GIOP_HELPS) classes/gnu/classpath/tools/giop/
- $(JCOMPILER) -d classes $(TOOLS_JAVA_FILES)
+ cp $(JARSIGNER_HELPS) classes/gnu/classpath/tools/jarsigner/
+ cp $(KEYTOOL_HELPS) classes/gnu/classpath/tools/keytool/
+ $(JCOMPILER) -d classes $(TOOLS_JAVA_FILES)
(cd classes; \
if test "$(ZIP)" != ""; then $(ZIP) -r ../$(TOOLS_ZIP) .; fi; \
if test "$(FASTJAR)" != ""; then $(FASTJAR) cf ../$(TOOLS_ZIP) .; fi; \
diff --git a/tools/README b/tools/README
index de8c2c5b4..dc049d3b5 100644
--- a/tools/README
+++ b/tools/README
@@ -39,6 +39,20 @@ in gnu.classpath.tools.rmi package):
research and backward-compatibile applications, as
Classpath supports the 1.5 feature to replace such
stubs by proxy classes.
+* REGISTRY - The persistent RMI naming service.
+* RMID - The persistent RMI activation daemon, supports the
+ java.rmi.activation package.
-
- \ No newline at end of file
+== Security tools ==
+
+Security tools (currently) are used for signing and verifying JAR files
+as well as (planned) generating and managing cryptographic tokens and
+credentials.
+
+The list of individual tools, the name of their main class that should be
+invoked by the Java launcher, and a summary of what they provide follows:
+
+* jarsigner gnu.classpath.tools.jarsigner.Main
+ A drop-in replacement for the "jarsigner" tool.
+
+
diff --git a/tools/appletviewer.c b/tools/appletviewer.c
new file mode 100644
index 000000000..2609ccaf6
--- /dev/null
+++ b/tools/appletviewer.c
@@ -0,0 +1,235 @@
+/* appletviewer.c -- a native appletviewer wrapper for VMs that
+ support the JNI invocation interface
+ 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. */
+
+#include <jni.h>
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include "config.h"
+
+#ifndef JNI_VERSION_1_2
+# error JNI version 1.2 or greater required
+#endif
+
+union env_union
+{
+ void *void_env;
+ JNIEnv *jni_env;
+};
+
+int
+main (int argc, const char** argv)
+{
+ union env_union tmp;
+ JNIEnv* env;
+ JavaVM* jvm;
+ JavaVMInitArgs vm_args;
+ jint result;
+ jclass class_id;
+ jmethodID method_id;
+ jstring str;
+ jclass string_class_id;
+ jobjectArray args_array;
+ char** non_vm_argv;
+ int non_vm_argc;
+ int i;
+ int classpath_found = 0;
+
+ env = NULL;
+ jvm = NULL;
+
+ vm_args.nOptions = 0;
+ vm_args.options = NULL;
+
+ non_vm_argc = 0;
+ non_vm_argv = NULL;
+
+ if (argc > 1)
+ {
+ for (i = 1; i < argc; i++)
+ {
+ if (!strncmp (argv[i], "-J", 2))
+ {
+ if (!strncmp (argv[i], "-J-Djava.class.path=", 20))
+ classpath_found = 1;
+
+ /* A virtual machine option. */
+ vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption));
+
+ if (vm_args.options == NULL)
+ {
+ g_printerr ("appletviewer: realloc failed.\n");
+ goto destroy;
+ }
+
+ if (strlen (argv[i]) == 2)
+ {
+ g_printerr ("appletviewer: the -J option must not be followed by a space.\n");
+ goto destroy;
+ }
+ else
+ vm_args.options[vm_args.nOptions++].optionString = g_strdup (argv[i] + 2);
+ }
+ else if (!strncmp (argv[i], "--version", 9)
+ && argv[i][9] == '\0')
+ {
+ g_print ("appletviewer (GCJ Applet Viewer) " PACKAGE_VERSION "\n");
+ exit (0);
+ }
+ else if (!strncmp (argv[i], "-debug", 6)
+ && argv[i][6] == '\0')
+ {
+ /* FIXME: Ignore for now. The debug option will be
+ unsupported until we have the ability to debug
+ bytecode. For now, just strip it out of the argument
+ list. */
+ }
+ else
+ {
+ non_vm_argv = (char**) realloc (non_vm_argv, (non_vm_argc + 1) * sizeof (char*));
+ if (non_vm_argv == NULL)
+ {
+ g_printerr ("appletviewer: realloc failed.\n");
+ goto destroy;
+ }
+ non_vm_argv[non_vm_argc++] = g_strdup (argv[i]);
+ }
+ }
+ }
+
+ if (!classpath_found)
+ {
+ /* Set the invocation classpath. */
+ vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption));
+
+ if (vm_args.options == NULL)
+ {
+ g_printerr ("appletviewer: realloc failed.\n");
+ goto destroy;
+ }
+
+ vm_args.options[vm_args.nOptions++].optionString = "-Djava.class.path=" "@datadir@/@PACKAGE@/tools.zip";
+ }
+
+ /* Terminate vm_args.options with a NULL element. */
+ vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption));
+ if (vm_args.options == NULL)
+ {
+ g_printerr ("appletviewer: realloc failed.\n");
+ goto destroy;
+ }
+ vm_args.options[vm_args.nOptions].optionString = NULL;
+
+ /* Terminate non_vm_argv with a NULL element. */
+ non_vm_argv = (char**) realloc (non_vm_argv, (non_vm_argc + 1) * sizeof (char*));
+ if (non_vm_argv == NULL)
+ {
+ g_printerr ("appletviewer: realloc failed.\n");
+ goto destroy;
+ }
+ non_vm_argv[non_vm_argc] = NULL;
+
+ vm_args.version = JNI_VERSION_1_2;
+ vm_args.ignoreUnrecognized = JNI_TRUE;
+
+ result = JNI_CreateJavaVM (&jvm, &tmp.void_env, &vm_args);
+
+ if (result < 0)
+ {
+ g_printerr ("appletviewer: couldn't create virtual machine\n");
+ goto destroy;
+ }
+
+ env = tmp.jni_env;
+
+ string_class_id = (*env)->FindClass (env, "java/lang/String");
+ if (string_class_id == NULL)
+ {
+ g_printerr ("appletviewer: FindClass failed.\n");
+ goto destroy;
+ }
+
+ args_array = (*env)->NewObjectArray (env, non_vm_argc, string_class_id, NULL);
+ if (args_array == NULL)
+ {
+ g_printerr ("appletviewer: NewObjectArray failed.\n");
+ goto destroy;
+ }
+
+ for (i = 0; i < non_vm_argc; i++)
+ {
+ str = (*env)->NewStringUTF (env, non_vm_argv[i]);
+ if (str == NULL)
+ {
+ g_printerr ("appletviewer: NewStringUTF failed.\n");
+ goto destroy;
+ }
+
+ (*env)->SetObjectArrayElement (env, args_array, i, str);
+ }
+
+ class_id = (*env)->FindClass (env, "gnu/classpath/tools/appletviewer/Main");
+ if (class_id == NULL)
+ {
+ g_printerr ("appletviewer: FindClass failed.\n");
+ goto destroy;
+ }
+
+ method_id = (*env)->GetStaticMethodID (env, class_id, "main", "([Ljava/lang/String;)V");
+
+ if (method_id == NULL)
+ {
+ g_printerr ("appletviewer: GetStaticMethodID failed.\n");
+ goto destroy;
+ }
+
+ (*env)->CallStaticVoidMethod (env, class_id, method_id, args_array);
+
+ destroy:
+
+ if (env != NULL)
+ {
+ if ((*env)->ExceptionOccurred (env))
+ (*env)->ExceptionDescribe (env);
+
+ if (jvm != NULL)
+ (*jvm)->DestroyJavaVM (jvm);
+ }
+
+ return 1;
+}
diff --git a/tools/appletviewer.in b/tools/appletviewer.in
new file mode 100644
index 000000000..61571d906
--- /dev/null
+++ b/tools/appletviewer.in
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+## Copyright (C) 2006 Free Software Foundation, Inc.
+##
+## This file is a 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 of the License, 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; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, 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.
+##
+##
+## A simple shell script to launch the GNU Classpath appletviewer tool.
+##
+
+prefix=@prefix@
+tools_dir=@datadir@/@PACKAGE@
+tools_cp=${tools_dir}/tools.zip
+
+# find the java executable...
+if [ -z "${JAVA}" ] ; then
+ if [ -n "${JAVA_HOME}" ] ; then
+ if [ -x "${JAVA_HOME}/jre/sh/java" ] ; then
+ JAVA="${JAVA_HOME}/jre/sh/java"
+ else
+ JAVA="${JAVA_HOME}/bin/java"
+ fi
+ else
+ JAVA=`which java 2> /dev/null `
+ if [ -z "${JAVA}" ] ; then
+ JAVA=java
+ fi
+ fi
+fi
+
+exec "${JAVA}" -Xbootclasspath/p:"${tools_cp}" gnu.classpath.tools.appletviewer.Main $@
diff --git a/tools/gnu/classpath/tools/HelpPrinter.java b/tools/gnu/classpath/tools/HelpPrinter.java
index 61a3e683b..89468918a 100644
--- a/tools/gnu/classpath/tools/HelpPrinter.java
+++ b/tools/gnu/classpath/tools/HelpPrinter.java
@@ -70,30 +70,47 @@ public class HelpPrinter
}
/**
- * Prints the help message and terminates.
+ * Prints the contents of the resource specified by the designated path.
*
- * @param helpResourcePath the path to the help resource, related to the
+ * @param helpResourcePath the path to a help resource, related to the
* HelpPrinter class.
*/
- public static void printHelpAndExit(String helpResourcePath)
+ public static void printHelp(String helpResourcePath)
{
InputStream in = HelpPrinter.class.getResourceAsStream(helpResourcePath);
- BufferedReader r = new BufferedReader(new InputStreamReader(in));
-
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
try
{
String s;
- while ((s = r.readLine()) != null)
- {
- System.out.println(s);
- }
- r.close();
+ while ((s = br.readLine()) != null)
+ System.out.println(s);
}
- catch (IOException e)
+ catch (IOException x)
{
System.err.print("Resource loading is broken:");
- e.printStackTrace();
+ x.printStackTrace(System.err);
+ }
+ finally
+ {
+ try
+ {
+ br.close();
+ }
+ catch (IOException ignored)
+ {
+ }
}
+ }
+
+ /**
+ * Prints the help message and terminates.
+ *
+ * @param helpResourcePath the path to the help resource, related to the
+ * HelpPrinter class.
+ */
+ public static void printHelpAndExit(String helpResourcePath)
+ {
+ printHelp(helpResourcePath);
System.exit(0);
}
}
diff --git a/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java b/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java
new file mode 100644
index 000000000..dfbedfe36
--- /dev/null
+++ b/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/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java b/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java
new file mode 100644
index 000000000..32ab31639
--- /dev/null
+++ b/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/tools/gnu/classpath/tools/appletviewer/AppletTag.java b/tools/gnu/classpath/tools/appletviewer/AppletTag.java
new file mode 100644
index 000000000..b2d7ccb2b
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/AppletTag.java
@@ -0,0 +1,485 @@
+/* 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();
+
+ // 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/tools/gnu/classpath/tools/appletviewer/AppletWarning.java b/tools/gnu/classpath/tools/appletviewer/AppletWarning.java
new file mode 100644
index 000000000..b2376a4cb
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/AppletWarning.java
@@ -0,0 +1,66 @@
+/* AppletWarning -- a security warning message display dialog
+ 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 javax.swing.JOptionPane;
+
+/**
+ * @author Michael Koch (konqueror@gmx.de)
+ */
+public class AppletWarning
+{
+ private static String TITLE = "WARNING";
+ private static boolean showWarning = false;
+
+ private static String MESSAGE =
+ "The current version of this applet plugin does not provide\n" +
+ "a security manager capable of handling Java (tm) applets. Applets\n" +
+ "have UNRESTRICTED access to your computer. This means they can do\n" +
+ "anything you can do, like deleting all your important data.\n\n" +
+ "Continue ?";
+
+ public static int show()
+ {
+ if (showWarning)
+ return JOptionPane.showConfirmDialog(null, MESSAGE, TITLE,
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE);
+ else
+ return JOptionPane.YES_OPTION;
+ }
+}
diff --git a/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java b/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java
new file mode 100644
index 000000000..7e118e931
--- /dev/null
+++ b/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/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java b/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java
new file mode 100644
index 000000000..bc0cc45e1
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java
@@ -0,0 +1,138 @@
+/* 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("unknown codebase");
+ }
+ }
+
+ /**
+ * 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 (String) 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/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java b/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java
new file mode 100644
index 000000000..9c937cc77
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java
@@ -0,0 +1,175 @@
+/* ConsoleDialog -- a console dialog for 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 java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Panel;
+import java.awt.TextArea;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+
+/**
+ * This class is a little dialog showing standard output and standard error output.
+ *
+ * @author Michael Koch (konqueror@gmx.de)
+ */
+public class ConsoleDialog extends Frame
+ implements ActionListener
+{
+ static class InternalOutputStream extends OutputStream
+ {
+ private ConsoleDialog console;
+
+ public InternalOutputStream(ConsoleDialog console)
+ {
+ super();
+ this.console = console;
+ }
+
+ public void write(int data) throws IOException
+ {
+ console.print(String.valueOf((char) data));
+ }
+ }
+
+ private TextArea textArea;
+ private Button buttonClear;
+ private Button buttonHide;
+ private PrintStream printStream;
+
+ /**
+ * Creates a console dialog object.
+ */
+ public ConsoleDialog()
+ {
+ super(Main.messages.getString("gcjwebplugin.console_title"));
+
+ setSize(400, 200);
+ setLayout(new BorderLayout());
+ addWindowListener(new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent event)
+ {
+ hide();
+ }
+ });
+
+ textArea = new TextArea();
+ textArea.setEditable(false);
+ add(textArea);
+
+ Panel panel = new Panel();
+ panel.setLayout(new FlowLayout());
+ add(panel, BorderLayout.SOUTH);
+
+ buttonClear = new Button(Main.messages.getString("gcjwebplugin.console_clear"));
+ buttonClear.addActionListener(this);
+ panel.add(buttonClear);
+
+ buttonHide = new Button(Main.messages.getString("gcjwebplugin.console_hide"));
+ buttonHide.addActionListener(this);
+ panel.add(buttonHide);
+
+ printStream = new PrintStream(new InternalOutputStream(this));
+ clearTextArea();
+ }
+
+ /**
+ * Clears the content of the textarea and inserts the initial text.
+ */
+ public void clearTextArea()
+ {
+ textArea.setText("");
+
+ println("java.vm.version: " + System.getProperty("java.vm.version"));
+ println("java.vm.vendor: " + System.getProperty("java.vm.vendor"));
+ }
+
+ /**
+ * Print a message into the console dialog.
+ *
+ * @param message the message to print.
+ */
+ public void print(String message)
+ {
+ textArea.append(message);
+ }
+
+ /**
+ * Print a line into the console dialog.
+ *
+ * @param message the line to print.
+ */
+ public void println(String message)
+ {
+ print(message + "\n");
+ }
+
+ /**
+ * Perform actions on button clicks inside the console dialog.
+ *
+ * @param event the event.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ if (event.getSource() == buttonHide)
+ hide(); // Hide console window.
+ else if (event.getSource() == buttonClear)
+ clearTextArea(); // Clear text area and insert standard messages.
+ }
+
+ /**
+ * Returns a <code>PrintStream</code> object that prints into the
+ * console dialog.
+ *
+ * @return the <code>PrintStream</code> object.
+ */
+ public PrintStream getPrintStream()
+ {
+ return printStream;
+ }
+}
diff --git a/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java b/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java
new file mode 100644
index 000000000..059dbee40
--- /dev/null
+++ b/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/tools/gnu/classpath/tools/appletviewer/Main.java b/tools/gnu/classpath/tools/appletviewer/Main.java
new file mode 100644
index 000000000..878b2be8a
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/Main.java
@@ -0,0 +1,303 @@
+/* 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.getopt.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.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ResourceBundle;
+
+
+class Main
+{
+ /**
+ * The localized strings are kept in a separate file.
+ */
+ public static final ResourceBundle messages = ResourceBundle.getBundle
+ ("gnu.classpath.tools.appletviewer.MessagesBundle");
+
+ 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("Error loading applet");
+
+ 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("usage: appletviewer [OPTION] --code=FILE | URL...");
+
+ OptionGroup attributeGroup = new OptionGroup("Applet tag options");
+
+ attributeGroup.add(new Option("code", Main.messages.getString
+ ("gcjwebplugin.code_description"),
+ "<code attribute>")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ code = argument;
+ }
+ });
+ attributeGroup.add(new Option("codebase", Main.messages.getString
+ ("gcjwebplugin.codebase_description"),
+ "<codebase attribute>")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ codebase = argument;
+ }
+ });
+ attributeGroup.add(new Option("archive", Main.messages.getString
+ ("gcjwebplugin.archive_description"),
+ "<archive attribute>")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ archive = argument;
+ }
+ });
+ attributeGroup.add(new Option("width", Main.messages.getString
+ ("gcjwebplugin.width_description"),
+ "<width attribute>")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ dimensions.width = Integer.parseInt(argument);
+ }
+ });
+ attributeGroup.add(new Option("height", Main.messages.getString
+ ("gcjwebplugin.height_description"),
+ "<height attribute>")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ dimensions.height = Integer.parseInt(argument);
+ }
+ });
+ attributeGroup.add(new Option("param", Main.messages.getString
+ ("gcjwebplugin.param_description"),
+ "<name>,<value>")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ parameters.add(argument);
+ }
+ });
+ OptionGroup pluginGroup = new OptionGroup("Plugin option");
+ pluginGroup.add(new Option("plugin", Main.messages.getString
+ ("gcjwebplugin.plugin_description"),
+ "<input pipe>,<output pipe>")
+ {
+ 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("Debugging option");
+ debuggingGroup.add(new Option ("verbose", Main.messages.getString
+ ("gcjwebplugin.verbose_description"),
+ null)
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ OptionGroup compatibilityGroup = new OptionGroup("Compatibility options");
+ compatibilityGroup.add(new Option("debug", Main.messages.getString
+ ("gcjwebplugin.debug_description"),
+ null)
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ // Currently ignored.
+ }
+ });
+ compatibilityGroup.add(new Option("encoding", Main.messages.getString
+ ("gcjwebplugin.encoding_description"),
+ "<character set>")
+ {
+ 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?
+ }
+ });
+ compatibilityGroup.add(new Option('J', Main.messages.getString
+ ("gcjwebplugin.j_description"),
+ "<virtual machine option>")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ // -J should be handled by the appletviewer wrapper binary.
+ // We add it here so that it shows up in the --help output.
+ }
+ });
+ 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)
+ {
+ InputStream in;
+ OutputStream out;
+
+ in = new FileInputStream(pipeInName);
+ out = new FileOutputStream(pipeOutName);
+
+ PluginAppletViewer.start(in, out);
+ }
+ else
+ {
+ 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(Main.messages.getString("gcjwebplugin.no_input_files"));
+ 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("raw arguments:");
+
+ for (int i = 0; i < args.length; i++)
+ System.out.println(" " + args[i]);
+ }
+ }
+}
diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java
new file mode 100644
index 000000000..a0e6acd12
--- /dev/null
+++ b/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)
+ {
+ System.err.println("showDocument failed: " + e);
+ }
+ }
+
+ public void showStatus(String status)
+ {
+ try
+ {
+ PluginAppletViewer.write("status " + status);
+ }
+ catch(IOException e)
+ {
+ System.err.println("showDocument failed: " + e);
+ }
+ }
+}
diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java
new file mode 100644
index 000000000..fdb8097b4
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java
@@ -0,0 +1,172 @@
+/* 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(" PIPE: applet viewer wrote: " + 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(" PIPE: applet viewer read: " + message);
+
+ if (message == null || message.equals("shutdown"))
+ {
+ // Close input/output channels to plugin.
+ pluginInputStream.close();
+ pluginOutputStream.close();
+
+ System.err.println("appletviewer: exiting plugin applet viewer");
+ System.exit(0);
+ }
+
+ return message;
+ }
+}
diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java
new file mode 100644
index 000000000..6d36e1cf0
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java
@@ -0,0 +1,454 @@
+/* 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;
+
+import javax.swing.JOptionPane;
+
+
+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 e 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());
+
+ int result = AppletWarning.show();
+ if (result == JOptionPane.NO_OPTION)
+ return;
+
+ 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/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java
new file mode 100644
index 000000000..a779f068a
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java
@@ -0,0 +1,75 @@
+/* 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("showDocument is not implemented in standalone mode");
+ }
+
+ // 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/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java
new file mode 100644
index 000000000..2b58f4b87
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java
@@ -0,0 +1,144 @@
+/* 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("appletviewer: option '--code' requires a class filename");
+ 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("parsed applet tags:");
+
+ for (int i = 0; i < appletTags.size(); i++)
+ {
+ AppletTag tag = (AppletTag) appletTags.get(i);
+
+ System.out.println(" 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/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java
new file mode 100644
index 000000000..3b337bf80
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java
@@ -0,0 +1,559 @@
+/* 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(Main.messages.getString("gcjwebplugin.menu_restart"));
+ restartItem.setEnabled(false);
+ restartItem.addActionListener(this);
+ reloadItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_reload"));
+ reloadItem.setEnabled(false);
+ reloadItem.addActionListener(this);
+ cancelItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_cancel"));
+ cancelItem.setEnabled(false);
+ cancelItem.addActionListener(this);
+ saveItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_save"));
+ saveItem.setEnabled(false);
+ saveItem.addActionListener(this);
+ startItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_start"));
+ startItem.setEnabled(false);
+ startItem.addActionListener(this);
+ cloneItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_clone"));
+ cloneItem.setEnabled(false);
+ cloneItem.addActionListener(this);
+ closeItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_close"));
+ closeItem.setEnabled(false);
+ closeItem.addActionListener(this);
+ tagItem =
+ new MenuItem(Main.messages.getString("gcjwebplugin.menu_tag"));
+ tagItem.setEnabled(false);
+ tagItem.addActionListener(this);
+ infoItem =
+ new MenuItem(Main.messages.getString("gcjwebplugin.menu_info"));
+ infoItem.setEnabled(false);
+ infoItem.addActionListener(this);
+ editItem =
+ new MenuItem(Main.messages.getString("gcjwebplugin.menu_edit"));
+ editItem.setEnabled(false);
+ editItem.addActionListener(this);
+ editItem.setEnabled(false);
+ encodingItem =
+ new MenuItem(Main.messages.getString("gcjwebplugin.menu_encoding"));
+ encodingItem.setEnabled(false);
+ encodingItem.addActionListener(this);
+ printItem =
+ new MenuItem(Main.messages.getString("gcjwebplugin.menu_print"));
+ printItem.setEnabled(false);
+ printItem.addActionListener(this);
+ propertiesItem =
+ new MenuItem(Main.messages.getString("gcjwebplugin.menu_properties"));
+ propertiesItem.setEnabled(false);
+ propertiesItem.addActionListener(this);
+ quitItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_quit"));
+ quitItem.addActionListener(this);
+
+ MenuBar menuBar = new MenuBar();
+ Menu menuApplet = new Menu(Main.messages.getString("gcjwebplugin.menu_title"));
+ 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("GCJ Applet Viewer: " + 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 e 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/tools/gnu/classpath/tools/appletviewer/TagParser.java b/tools/gnu/classpath/tools/appletviewer/TagParser.java
new file mode 100644
index 000000000..68dce97e0
--- /dev/null
+++ b/tools/gnu/classpath/tools/appletviewer/TagParser.java
@@ -0,0 +1,302 @@
+/* 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();
+ }
+
+ t.parameters.put(key.toLowerCase(), val);
+ }
+ }
+
+ /**
+ * Parses the archive string and returns a list.
+ *
+ * @param 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/tools/gnu/classpath/tools/common/CallbackUtil.java b/tools/gnu/classpath/tools/common/CallbackUtil.java
new file mode 100644
index 000000000..398bb6cae
--- /dev/null
+++ b/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/tools/gnu/classpath/tools/common/ProviderUtil.java b/tools/gnu/classpath/tools/common/ProviderUtil.java
new file mode 100644
index 000000000..8d0434433
--- /dev/null
+++ b/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/tools/gnu/classpath/tools/common/SecurityProviderInfo.java b/tools/gnu/classpath/tools/common/SecurityProviderInfo.java
new file mode 100644
index 000000000..e12ee4fe3
--- /dev/null
+++ b/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/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java b/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java
new file mode 100644
index 000000000..be382a7a4
--- /dev/null
+++ b/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java
@@ -0,0 +1,71 @@
+/* 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.getopt;
+
+import gnu.classpath.Configuration;
+
+/**
+ * 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)
+ {
+ return (programName + " (GNU Classpath) "
+ + Configuration.CLASSPATH_VERSION
+ + "\n\n"
+ + "Copyright 2006 Free Software Foundation, Inc.\n"
+ + "This is free software; see the source for copying conditions. There is NO\n"
+ + "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
+
+ }
+
+ public ClasspathToolParser(String programName)
+ {
+ super(programName, getVersionString(programName));
+ }
+
+ public ClasspathToolParser(String programName, boolean longOnly)
+ {
+ super(programName, getVersionString(programName), longOnly);
+ }
+}
diff --git a/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java b/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java
new file mode 100644
index 000000000..0c44745c9
--- /dev/null
+++ b/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java
@@ -0,0 +1,61 @@
+/* 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);
+}
diff --git a/tools/gnu/classpath/tools/getopt/Option.java b/tools/gnu/classpath/tools/getopt/Option.java
new file mode 100644
index 000000000..e54aaa103
--- /dev/null
+++ b/tools/gnu/classpath/tools/getopt/Option.java
@@ -0,0 +1,201 @@
+/* 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.
+ */
+public abstract class Option
+{
+ private char shortName;
+
+ private String longName;
+
+ private String description;
+
+ private String argumentName;
+
+ /**
+ * 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)
+ {
+ 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)
+ {
+ this.shortName = shortName;
+ this.description = description;
+ this.argumentName = argumentName;
+ }
+
+ /**
+ * 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)
+ {
+ 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)
+ {
+ this.shortName = shortName;
+ this.longName = longName;
+ this.argumentName = argumentName;
+ this.description = description;
+ }
+
+ /**
+ * 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()
+ {
+ // FIXME: localization.
+ return description;
+ }
+
+ /**
+ * 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/tools/gnu/classpath/tools/getopt/OptionException.java b/tools/gnu/classpath/tools/getopt/OptionException.java
new file mode 100644
index 000000000..a09d716f4
--- /dev/null
+++ b/tools/gnu/classpath/tools/getopt/OptionException.java
@@ -0,0 +1,52 @@
+/* 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);
+ }
+}
diff --git a/tools/gnu/classpath/tools/getopt/OptionGroup.java b/tools/gnu/classpath/tools/getopt/OptionGroup.java
new file mode 100644
index 000000000..d83b273ba
--- /dev/null
+++ b/tools/gnu/classpath/tools/getopt/OptionGroup.java
@@ -0,0 +1,171 @@
+/* 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.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * 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
+{
+ 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;
+ }
+
+ /**
+ * 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)
+ {
+ // Compute maximum lengths.
+ int maxArgLen = 0;
+ int maxShortLen = 0;
+ Iterator 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 (option.getShortName() != '\0')
+ {
+ // The name of the option plus some padding.
+ thisArgLen += 4;
+ }
+ maxShortLen = Math.max(thisArgLen, maxShortLen);
+ if (option.getLongName() != null)
+ {
+ // FIXME: different if parsing in 'long option only'
+ // mode.
+ thisArgLen += 2 + option.getLongName().length();
+ }
+ // We only need to add the argument name in once,
+ // and we don't let it contribute to the width of
+ // the short 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)
+ {
+ out.print(' ');
+ out.print(argName);
+ column += 1 + argName.length();
+ }
+ out.print(" ");
+ }
+ else
+ out.print(", ");
+ column += 2;
+ }
+ for (; column < maxShortLen; ++column)
+ out.print(' ');
+ if (option.getLongName() != null)
+ {
+ out.print("--");
+ out.print(option.getLongName());
+ column += 2 + option.getLongName().length();
+ if (argName != null)
+ {
+ out.print("=" + argName);
+ column += 1 + argName.length();
+ }
+ }
+ for (; column < maxArgLen; ++column)
+ out.print(' ');
+ // FIXME: should have a better heuristic for padding.
+ out.print(" ");
+ out.println(option.getDescription());
+ }
+ }
+}
diff --git a/tools/gnu/classpath/tools/getopt/Parser.java b/tools/gnu/classpath/tools/getopt/Parser.java
new file mode 100644
index 000000000..8d70c01d0
--- /dev/null
+++ b/tools/gnu/classpath/tools/getopt/Parser.java
@@ -0,0 +1,314 @@
+/* Parser.java - parse 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.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * 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
+{
+ private String programName;
+
+ private String headerText;
+
+ private String footerText;
+
+ private boolean longOnly;
+
+ private ArrayList options = new ArrayList();
+
+ private ArrayList optionGroups = new ArrayList();
+
+ private OptionGroup defaultGroup = new OptionGroup();
+
+ // 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);
+ }
+
+ /**
+ * 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;
+ defaultGroup.add(new Option("help", "print this help, then exit")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ printHelp(System.out);
+ System.exit(0);
+ }
+ });
+ defaultGroup.add(new Option("version", "print version number, then exit")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ System.out.println(versionString);
+ System.exit(0);
+ }
+ });
+ add(defaultGroup);
+ }
+
+ /**
+ * Set the header text that is printed by --help.
+ *
+ * @param headerText the header text
+ */
+ public void setHeader(String headerText)
+ {
+ this.headerText = headerText;
+ }
+
+ /**
+ * Set the footer text that is printed by --help.
+ *
+ * @param footerText the footer text
+ */
+ public 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)
+ {
+ options.add(opt);
+ defaultGroup.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)
+ {
+ options.addAll(group.options);
+ optionGroups.add(group);
+ }
+
+ void printHelp(PrintStream out)
+ {
+ if (headerText != null)
+ {
+ out.println(headerText);
+ out.println();
+ }
+
+ Iterator it = optionGroups.iterator();
+ while (it.hasNext())
+ {
+ OptionGroup group = (OptionGroup) it.next();
+ group.printHelp(out);
+ out.println();
+ }
+
+ if (footerText != null)
+ out.println(footerText);
+ }
+
+ private String getArgument(String request) throws OptionException
+ {
+ ++currentIndex;
+ if (currentIndex >= args.length)
+ throw new OptionException("option '" + request + "' requires an argument");
+ 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);
+ 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 (found == null)
+ throw new OptionException("unrecognized option '" + real + "'");
+ String argument = null;
+ if (found.getTakesArgument())
+ {
+ if (eq == - 1)
+ argument = getArgument(real);
+ else
+ argument = option.substring(eq + 1);
+ }
+ else if (eq != - 1)
+ {
+ throw new OptionException("option '" + real.substring(0, eq + index)
+ + "' doesn't allow an argument");
+ }
+ found.parsed(argument);
+ }
+
+ private void handleShortOption(char option) throws OptionException
+ {
+ Option found = null;
+ for (int i = options.size() - 1; i >= 0; --i)
+ {
+ Option opt = (Option) options.get(i);
+ if (option == opt.getShortName())
+ {
+ found = opt;
+ break;
+ }
+ }
+ if (found == null)
+ throw new OptionException("unrecognized option '-" + option + "'");
+ String argument = null;
+ if (found.getTakesArgument())
+ argument = getArgument("-" + option);
+ found.parsed(argument);
+ }
+
+ private void handleShortOptions(String option) throws OptionException
+ {
+ for (int i = 1; i < option.length(); ++i)
+ {
+ handleShortOption(option.charAt(i));
+ }
+ }
+
+ /**
+ * 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)
+ {
+ try
+ {
+ args = inArgs;
+ for (currentIndex = 0; currentIndex < args.length; ++currentIndex)
+ {
+ if (args[currentIndex].length() == 0
+ || args[currentIndex].charAt(0) != '-'
+ || "-".equals(args[currentIndex]))
+ {
+ files.notifyFile(args[currentIndex]);
+ continue;
+ }
+ if ("--".equals(args[currentIndex]))
+ 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]);
+ }
+ catch (OptionException err)
+ {
+ System.err.println(programName + ": " + err.getMessage());
+ System.err.println(programName + ": Try '" + programName
+ + " --help' for more information.");
+ 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/tools/gnu/classpath/tools/giop/GRMIC.java b/tools/gnu/classpath/tools/giop/GRMIC.java
index 16ff96f56..a372cfd66 100644
--- a/tools/gnu/classpath/tools/giop/GRMIC.java
+++ b/tools/gnu/classpath/tools/giop/GRMIC.java
@@ -17,23 +17,7 @@ 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.giop;
@@ -105,6 +89,10 @@ public class GRMIC
verbose = true;
compiler.setVerbose(true);
}
+ else if (c.equals("-force"))
+ {
+ compiler.setForce(true);
+ }
else if (c.equals("-d"))
{
int f = i + 1;
diff --git a/tools/gnu/classpath/tools/giop/GRMIC.txt b/tools/gnu/classpath/tools/giop/GRMIC.txt
index fcde83895..08aaf148f 100644
--- a/tools/gnu/classpath/tools/giop/GRMIC.txt
+++ b/tools/gnu/classpath/tools/giop/GRMIC.txt
@@ -19,6 +19,9 @@ Usage: grmic <options> <class names>
-help Print this help text
-v Print version
-verbose Verbose output
+ -force Try to generate code even if the input classes seem not
+ consistent with RMI specification.
+
and <class names> can include one or more non abstract classes that implement
Remote and are accessible via current class path.
diff --git a/tools/gnu/classpath/tools/giop/IorParser.java b/tools/gnu/classpath/tools/giop/IorParser.java
index 7d70c8aca..411b8997d 100644
--- a/tools/gnu/classpath/tools/giop/IorParser.java
+++ b/tools/gnu/classpath/tools/giop/IorParser.java
@@ -17,23 +17,7 @@ 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.giop;
diff --git a/tools/gnu/classpath/tools/giop/grmic/CompilationError.java b/tools/gnu/classpath/tools/giop/grmic/CompilationError.java
index c6b3e56e8..d1fa814ee 100644
--- a/tools/gnu/classpath/tools/giop/grmic/CompilationError.java
+++ b/tools/gnu/classpath/tools/giop/grmic/CompilationError.java
@@ -17,23 +17,7 @@ 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.giop.grmic;
diff --git a/tools/gnu/classpath/tools/giop/grmic/Generator.java b/tools/gnu/classpath/tools/giop/grmic/Generator.java
index a45e8d398..17ab821ec 100644
--- a/tools/gnu/classpath/tools/giop/grmic/Generator.java
+++ b/tools/gnu/classpath/tools/giop/grmic/Generator.java
@@ -17,23 +17,7 @@ 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.giop.grmic;
diff --git a/tools/gnu/classpath/tools/giop/grmic/GiopIo.java b/tools/gnu/classpath/tools/giop/grmic/GiopIo.java
index 3714c4ce4..0e0df7bc5 100644
--- a/tools/gnu/classpath/tools/giop/grmic/GiopIo.java
+++ b/tools/gnu/classpath/tools/giop/grmic/GiopIo.java
@@ -17,23 +17,7 @@ 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.giop.grmic;
diff --git a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
index c19f635c6..4beba1c9f 100644
--- a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
+++ b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
@@ -17,23 +17,7 @@ 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.giop.grmic;
@@ -115,6 +99,11 @@ public class GiopRmicCompiler
* Verbose output
*/
protected boolean verbose = false;
+
+ /**
+ * Force mode - do not check the exceptions
+ */
+ protected boolean force = false;
/**
* Clear data, preparing for the next compilation.
@@ -204,7 +193,7 @@ public class GiopRmicCompiler
remEx = true;
break;
}
- if (! remEx)
+ if (! remEx && !force)
throw new CompilationError(m[i].getName() + ", defined in "
+ c.getName()
+ ", does not throw "
@@ -483,6 +472,14 @@ public class GiopRmicCompiler
{
warnings = warn;
}
+
+ /**
+ * Set the error ignore mode.
+ */
+ public void setForce(boolean isforce)
+ {
+ force = isforce;
+ }
/**
* Get the package name.
diff --git a/tools/gnu/classpath/tools/giop/grmic/HashFinder.java b/tools/gnu/classpath/tools/giop/grmic/HashFinder.java
index 216e73953..2efdb1e76 100644
--- a/tools/gnu/classpath/tools/giop/grmic/HashFinder.java
+++ b/tools/gnu/classpath/tools/giop/grmic/HashFinder.java
@@ -1,3 +1,25 @@
+/* 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.
+*/
+
+
package gnu.classpath.tools.giop.grmic;
import java.util.HashSet;
diff --git a/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java b/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java
index 9a44fad79..80148d51a 100644
--- a/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java
+++ b/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java
@@ -17,23 +17,7 @@ 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.giop.grmic;
diff --git a/tools/gnu/classpath/tools/jar/Action.java b/tools/gnu/classpath/tools/jar/Action.java
new file mode 100644
index 000000000..fea60f797
--- /dev/null
+++ b/tools/gnu/classpath/tools/jar/Action.java
@@ -0,0 +1,50 @@
+/* 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/tools/gnu/classpath/tools/jar/Creator.java b/tools/gnu/classpath/tools/jar/Creator.java
new file mode 100644
index 000000000..a636fca6b
--- /dev/null
+++ b/tools/gnu/classpath/tools/jar/Creator.java
@@ -0,0 +1,192 @@
+/* Creator.java - create a new 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.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.util.ArrayList;
+import java.util.Iterator;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public class Creator
+ extends Action
+{
+ ZipOutputStream outputStream;
+
+ 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
+ {
+ 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();
+
+ if (verbose)
+ {
+ long csize = entry.getCompressedSize();
+ long perc;
+ if (size == 0)
+ perc = 0;
+ else
+ perc = 100 - (100 * csize) / size;
+ System.out.println("adding: " + filename + " (in=" + size + ") (out="
+ + entry.getSize() + ") (stored " + perc + "%)");
+ }
+ }
+
+ protected void writeFile(File file, String filename, boolean verbose)
+ throws IOException
+ {
+ boolean isDirectory = file.isDirectory();
+ InputStream inputStream = null;
+ if (isDirectory)
+ {
+ if (filename.charAt(filename.length() - 1) != '/')
+ filename += '/';
+ }
+ else
+ inputStream = new FileInputStream(file);
+ writeFile(isDirectory, inputStream, filename, verbose);
+ }
+
+ private void addEntries(ArrayList 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 getAllEntries(Main parameters)
+ {
+ Iterator it = parameters.entries.iterator();
+ ArrayList allEntries = new ArrayList();
+ while (it.hasNext())
+ {
+ Entry entry = (Entry) it.next();
+ addEntries(allEntries, entry);
+ }
+ return allEntries;
+ }
+
+ protected ArrayList writeCommandLineEntries(Main parameters, File zipFile)
+ throws IOException
+ {
+ outputStream = new ZipOutputStream(
+ new BufferedOutputStream(
+ new FileOutputStream(
+ zipFile)));
+ outputStream.setMethod(parameters.storageMode);
+ ArrayList allEntries = getAllEntries(parameters);
+ Iterator it = parameters.entries.iterator();
+ while (it.hasNext())
+ {
+ Entry entry = (Entry) it.next();
+ writeFile(entry.file, entry.name, parameters.verbose);
+ }
+ return allEntries;
+ }
+
+ protected void close() throws IOException
+ {
+ // FIXME: handle manifest options here.
+ // FIXME: handle index file here ...?
+ outputStream.finish();
+ outputStream.close();
+ }
+
+ public void run(Main parameters) throws IOException
+ {
+ writeCommandLineEntries(parameters, parameters.archiveFile);
+ close();
+ }
+}
diff --git a/tools/gnu/classpath/tools/jar/Entry.java b/tools/gnu/classpath/tools/jar/Entry.java
new file mode 100644
index 000000000..aa8679aab
--- /dev/null
+++ b/tools/gnu/classpath/tools/jar/Entry.java
@@ -0,0 +1,60 @@
+/* Entry.java - represent a single file to write to a 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.io.File;
+
+public class Entry
+{
+ public File file;
+
+ public String name;
+
+ public Entry(File file, String name)
+ {
+ this.file = file;
+ this.name = name;
+ }
+
+ public Entry(File file)
+ {
+ this.file = file;
+ this.name = file.toString();
+ }
+}
diff --git a/tools/gnu/classpath/tools/jar/Extractor.java b/tools/gnu/classpath/tools/jar/Extractor.java
new file mode 100644
index 000000000..245f5e36c
--- /dev/null
+++ b/tools/gnu/classpath/tools/jar/Extractor.java
@@ -0,0 +1,100 @@
+/* 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.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class Extractor
+ extends Action
+{
+ 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
+ {
+ ZipFile zip = new ZipFile(parameters.archiveFile);
+ Enumeration e = zip.entries();
+ while (e.hasMoreElements())
+ {
+ ZipEntry entry = (ZipEntry) e.nextElement();
+ File file = new File(entry.getName());
+ if (entry.isDirectory())
+ {
+ if (file.mkdirs())
+ {
+ if (parameters.verbose)
+ System.out.println(" created: " + file);
+ }
+ continue;
+ }
+
+ File parent = file.getParentFile();
+ if (parent != null)
+ parent.mkdirs();
+
+ InputStream input = zip.getInputStream(entry);
+ copyFile(input, file);
+ input.close();
+
+ if (parameters.verbose)
+ {
+ String leader = (entry.getMethod() == ZipEntry.STORED ? " extracted"
+ : " inflated");
+ System.out.println(leader + ": " + file);
+ }
+ }
+ }
+}
diff --git a/tools/gnu/classpath/tools/jar/Lister.java b/tools/gnu/classpath/tools/jar/Lister.java
new file mode 100644
index 000000000..fe5792e76
--- /dev/null
+++ b/tools/gnu/classpath/tools/jar/Lister.java
@@ -0,0 +1,84 @@
+/* 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.File;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class Lister
+ extends Action
+{
+ private void listJar(File jarFile, boolean verbose) throws IOException
+ {
+ ZipFile zipFile = new ZipFile(jarFile);
+ Enumeration i = zipFile.entries();
+ MessageFormat format = null;
+ if (verbose)
+ format = new MessageFormat(" {0,date,E M dd HH:mm:ss z yyyy} {1}");
+ while (i.hasMoreElements())
+ {
+ ZipEntry entry = (ZipEntry) i.nextElement();
+ if (verbose)
+ {
+ // No easy way to right-justify the size using
+ // MessageFormat -- how odd.
+ long size = entry.getSize();
+ 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());
+ }
+ zipFile.close();
+ }
+
+ public void run(Main parameters) throws IOException
+ {
+ listJar(parameters.archiveFile, parameters.verbose);
+ }
+}
diff --git a/tools/gnu/classpath/tools/jar/Main.java b/tools/gnu/classpath/tools/jar/Main.java
new file mode 100644
index 000000000..ee4da3c27
--- /dev/null
+++ b/tools/gnu/classpath/tools/jar/Main.java
@@ -0,0 +1,225 @@
+/* Main.java - jar program main()
+ 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 gnu.classpath.tools.getopt.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.File;
+import java.io.IOException;
+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 entries = new ArrayList();
+
+ // Used only while parsing.
+ String changedDirectory;
+
+ 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 void parsed(String argument) throws OptionException
+ {
+ if (operationMode != null)
+ throw new OptionException("operation mode already specified");
+ operationMode = mode;
+ }
+ }
+
+ private Parser initializeParser()
+ {
+ Parser p = new ClasspathToolParser("jar");
+ p.setHeader("Usage: jar -ctxu [OPTIONS] jar-file [-C DIR FILE] FILE...");
+
+ OptionGroup grp = new OptionGroup("Operation mode");
+ grp.add(new ModeOption('c', "create a new archive", Creator.class));
+ grp.add(new ModeOption('x', "extract from archive", Extractor.class));
+ grp.add(new ModeOption('t', "list archive contents", Lister.class));
+ grp.add(new ModeOption('u', "update archive", Updater.class));
+ p.add(grp);
+
+ grp = new OptionGroup("Operation modifiers");
+ grp.add(new Option('f', "specify archive file name", "FILE")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ // FIXME: error if already set.
+ archiveFile = new File(argument);
+ }
+ });
+ grp.add(new Option('0', "store only; no ZIP compression")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ storageMode = ZipOutputStream.STORED;
+ }
+ });
+ grp.add(new Option('v', "verbose operation")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+ grp.add(new Option('M', "do not create a manifest file")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ wantManifest = false;
+ }
+ });
+ grp.add(new Option('m', "specify manifest file", "FILE")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ manifestFile = new File(argument);
+ }
+ });
+ // -@
+ p.add(grp);
+
+ grp = new OptionGroup("File name selection");
+ grp.add(new Option('C', "change to directory before the next file",
+ "DIR FILE")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ changedDirectory = argument;
+ }
+ });
+ p.add(grp);
+ // -i - need to parse classes
+
+ return p;
+ }
+
+ private void run(String[] args) throws OptionException,
+ InstantiationException, IllegalAccessException, IOException
+ {
+ Parser p = initializeParser();
+ // Special hack to emulate old tar-style commands.
+ if (args[0].charAt(0) != '-')
+ args[0] = '-' + args[0];
+ p.parse(args, new HandleFile());
+ if (operationMode == null)
+ throw new OptionException("must specify one of -t, -c, -u, or -x");
+ if (changedDirectory != null)
+ throw new OptionException("-C argument requires both directory and filename");
+ Action t = (Action) operationMode.newInstance();
+ t.run(this);
+ }
+
+ public static void main(String[] args)
+ {
+ Main jarprogram = new Main();
+ try
+ {
+ jarprogram.run(args);
+ }
+ catch (OptionException arg)
+ {
+ System.err.println("jar: " + arg.getMessage());
+ System.exit(1);
+ }
+ catch (Exception e)
+ {
+ System.err.println("jar: internal error:");
+ e.printStackTrace(System.err);
+ System.exit(1);
+ }
+ }
+}
diff --git a/tools/gnu/classpath/tools/jar/Updater.java b/tools/gnu/classpath/tools/jar/Updater.java
new file mode 100644
index 000000000..9046b42b0
--- /dev/null
+++ b/tools/gnu/classpath/tools/jar/Updater.java
@@ -0,0 +1,81 @@
+/* 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.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class Updater
+ extends Creator
+{
+ public void run(Main parameters) throws IOException
+ {
+ // Write all the new entries to a temporary file.
+ File tmpFile = File.createTempFile("jarcopy", null);
+ ArrayList newEntries = writeCommandLineEntries(parameters, tmpFile);
+ HashSet set = new HashSet();
+ Iterator it = newEntries.iterator();
+ while (it.hasNext())
+ {
+ Entry entry = (Entry) it.next();
+ set.add(entry.name);
+ }
+
+ // Now read the old file and copy extra entries to the new file.
+ ZipFile zip = new ZipFile(parameters.archiveFile);
+ Enumeration e = zip.entries();
+ while (e.hasMoreElements())
+ {
+ ZipEntry entry = (ZipEntry) e.nextElement();
+ if (set.contains(entry.getName()))
+ continue;
+ writeFile(entry.isDirectory(), zip.getInputStream(entry),
+ zip.getName(), parameters.verbose);
+ }
+
+ close();
+ tmpFile.renameTo(parameters.archiveFile);
+ }
+}
diff --git a/tools/gnu/classpath/tools/jarsigner/HashUtils.java b/tools/gnu/classpath/tools/jarsigner/HashUtils.java
new file mode 100644
index 000000000..2286063f1
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/HashUtils.java
@@ -0,0 +1,122 @@
+/* Utils.java -- Utility methods for JAR file signing/verification
+ 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.java.security.hash.Sha160;
+import gnu.java.security.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();
+ 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();
+ 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/tools/gnu/classpath/tools/jarsigner/JarSigner.java b/tools/gnu/classpath/tools/jarsigner/JarSigner.java
new file mode 100644
index 000000000..40bee9fe9
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/JarSigner.java
@@ -0,0 +1,167 @@
+/* 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.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
+ {
+ 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;
+ log.finest("Processing " + sfFileName); //$NON-NLS-1$
+ JarEntry sfEntry = new JarEntry(sfFileName);
+ sfEntry.setTime(System.currentTimeMillis());
+ outSignedJarFile.putNextEntry(sfEntry);
+ sfHelper.writeSF(outSignedJarFile);
+ log.finer("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;
+ log.finest("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());
+ log.finer("Created .DSA file"); //$NON-NLS-1$
+ if (main.isVerbose())
+ System.out.println(Messages.getString("JarSigner.11") + dsaFileName); //$NON-NLS-1$
+
+ // cleanup
+ outSignedJarFile.close();
+ fos.close();
+ signedJarFile.renameTo(new File(main.getSignedJarFileName()));
+ log.finer("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$
+
+ 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/tools/gnu/classpath/tools/jarsigner/JarVerifier.java b/tools/gnu/classpath/tools/jarsigner/JarVerifier.java
new file mode 100644
index 000000000..f80147dfa
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/JarVerifier.java
@@ -0,0 +1,339 @@
+/* JarVerifier.java -- The verification 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.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.Certificate;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+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 entryHashes = new HashMap();
+
+ JarVerifier(Main main)
+ {
+ super();
+
+ this.main = main;
+ }
+
+ void start() throws Exception
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ String jarFileName = main.getJarFileName();
+ jarFile = new JarFile(jarFileName);
+
+ // 1. find all signature (.SF) files
+ List sfFiles = new ArrayList();
+ 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 (Iterator it = sfFiles.iterator(); it.hasNext(); )
+ {
+ String alias = (String) it.next();
+ 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)));
+ }
+
+ 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
+ {
+ log.entering(this.getClass().getName(), "verifySF"); //$NON-NLS-1$
+ log.finest("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$
+
+ log.finest("\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();
+ log.finest("--- 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);
+ log.finer("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
+ {
+ 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 entries = new HashMap();
+ 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 (Iterator it = entries.keySet().iterator(); it.hasNext();)
+ {
+ Entry me = (Entry) it.next();
+ String name = (String) me.getKey();
+ attr = (Attributes) me.getValue();
+ hash = attr.getValue(Main.DIGEST_ATTR);
+ result = verifySFEntry(name, hash);
+ if (! result)
+ break;
+ }
+
+ log.exiting(this.getClass().getName(), "verifySFEntries",
+ Boolean.valueOf(result)); //$NON-NLS-1$
+ 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);
+ log.finest("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/tools/gnu/classpath/tools/jarsigner/Main.java b/tools/gnu/classpath/tools/jarsigner/Main.java
new file mode 100644
index 000000000..f460a96cc
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/Main.java
@@ -0,0 +1,567 @@
+/* Main.java -- JAR signing and verification tool not unlike jarsigner
+ 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.SystemProperties;
+import gnu.classpath.tools.HelpPrinter;
+import gnu.classpath.tools.common.CallbackUtil;
+import gnu.classpath.tools.common.ProviderUtil;
+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.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
+{
+ private static final Logger log = Logger.getLogger(Main.class.getName());
+ private static final String HELP_PATH = "jarsigner/jarsigner.txt"; //$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);
+
+ private boolean verify;
+ private String ksURL;
+ private String ksType;
+ private String password;
+ private String ksPassword;
+ private String sigFileName;
+ private String signedJarFileName;
+ private boolean verbose;
+ private boolean certs;
+ private boolean internalSF;
+ private boolean sectionsOnly;
+ private String providerClassName;
+ private String jarFileName;
+ private 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;
+
+ private Main()
+ {
+ super();
+ }
+
+ public static final void main(String[] args)
+ {
+ log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$
+
+ Main tool = new Main();
+ try
+ {
+ tool.processArgs(args);
+ tool.start();
+ }
+ catch (SecurityException x)
+ {
+ 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)
+ {
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getString("Main.9") + x); //$NON-NLS-1$
+ }
+
+ tool.teardown();
+
+ log.exiting(Main.class.getName(), "main"); //$NON-NLS-1$
+ // System.exit(0);
+ }
+
+ // helper methods -----------------------------------------------------------
+
+ /**
+ * 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 exceptio occurs during the process.
+ */
+ private void processArgs(String[] args) throws Exception
+ {
+ log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$
+
+ HelpPrinter.checkHelpKey(args, HELP_PATH);
+ if (args == null || args.length == 0)
+ HelpPrinter.printHelpAndExit(HELP_PATH);
+
+ int limit = args.length;
+ log.finest("args.length=" + limit); //$NON-NLS-1$
+ int i = 0;
+ String opt;
+ while (i < limit)
+ {
+ opt = args[i++];
+ log.finest("args[" + (i - 1) + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-verify".equals(opt)) // -verify //$NON-NLS-1$
+ verify = true;
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ ksURL = args[i++];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ ksType = args[i++];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ ksPassword = args[i++];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ password = args[i++];
+ else if ("-sigfile".equals(opt)) // -sigfile NAME //$NON-NLS-1$
+ sigFileName = args[i++];
+ else if ("-signedjar".equals(opt)) // -signedjar FILE_NAME //$NON-NLS-1$
+ signedJarFileName = args[i++];
+ else if ("-verbose".equals(opt)) // -verbose //$NON-NLS-1$
+ verbose = true;
+ else if ("-certs".equals(opt)) // -certs //$NON-NLS-1$
+ certs = true;
+ else if ("-internalsf".equals(opt)) // -internalsf //$NON-NLS-1$
+ internalSF = true;
+ else if ("-sectionsonly".equals(opt)) // -sectionsonly //$NON-NLS-1$
+ sectionsOnly = true;
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ providerClassName = args[i++];
+ else
+ {
+ jarFileName = opt;
+ if (! verify)
+ alias = args[i++];
+
+ break;
+ }
+ }
+
+ if (i < limit) // more options than needed
+ log.fine("Last argument is assumed at index #" + (i - 1) //$NON-NLS-1$
+ + ". Remaining arguments (" + args[i] //$NON-NLS-1$
+ + "...) will be ignored"); //$NON-NLS-1$
+
+ setupCommonParams();
+ if (verify)
+ {
+ log.finer("Will verify with the following parameters:"); //$NON-NLS-1$
+ log.finer(" jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer("Options:"); //$NON-NLS-1$
+ log.finer(" provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" verbose ? " + verbose); //$NON-NLS-1$
+ log.finer(" certs ? " + certs); //$NON-NLS-1$
+ log.finer(" internalsf ? " + internalSF); //$NON-NLS-1$
+ log.finer(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$
+ }
+ else // sign
+ {
+ setupSigningParams();
+
+ log.finer("Will sign with the following parameters:"); //$NON-NLS-1$
+ log.finer(" jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" alias = '" + alias + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer("Options:"); //$NON-NLS-1$
+ log.finer(" keystore = '" + ksURL + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" storetype = '" + ksType + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" storepass = '" + ksPassword + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" keypass = '" + password + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" sigfile = '" + sigFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" signedjar = '" + signedJarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ log.finer(" verbose ? " + verbose); //$NON-NLS-1$
+ log.finer(" internalsf ? " + internalSF); //$NON-NLS-1$
+ log.finer(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$
+ }
+
+ 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
+ {
+ 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();
+ }
+
+ 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()
+ {
+ log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+
+ if (providerInstalled)
+ ProviderUtil.removeProvider(provider.getName());
+
+ 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
+ {
+ log.entering(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$
+
+ if (jarFileName == null)
+ HelpPrinter.printHelpAndExit(HELP_PATH);
+
+ 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)
+ log.finer("Provider " + providerName + " is already installed"); //$NON-NLS-1$ //$NON-NLS-2$
+ else // install it
+ installNewProvider();
+ }
+
+ if (! verbose && certs)
+ {
+ log.fine("Option <certs> is set but <verbose> is not. Ignored"); //$NON-NLS-1$
+ certs = false;
+ }
+
+ 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()
+ {
+ log.entering(this.getClass().getName(), "installNewProvider"); //$NON-NLS-1$
+
+ providerInstalled = ProviderUtil.addProvider(provider) != -1;
+
+ 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
+ {
+ 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 (alias == null)
+ HelpPrinter.printHelpAndExit(HELP_PATH);
+
+ 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);
+ log.finest(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;
+
+ 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;
+ }
+}
diff --git a/tools/gnu/classpath/tools/jarsigner/Messages.java b/tools/gnu/classpath/tools/jarsigner/Messages.java
new file mode 100644
index 000000000..284639115
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/Messages.java
@@ -0,0 +1,115 @@
+/* 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.jarsigner;
+
+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.MessageBundle"; //$NON-NLS-1$
+ 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 consisiting 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)
+ {
+ 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/tools/gnu/classpath/tools/jarsigner/SFHelper.java b/tools/gnu/classpath/tools/jarsigner/SFHelper.java
new file mode 100644
index 000000000..b4e5cc193
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/SFHelper.java
@@ -0,0 +1,373 @@
+/* SFHelper -- A .SF file helper
+ 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.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.X509CRL;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.ArrayList;
+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
+{
+ // Constants and fields
+ // --------------------------------------------------------------------------
+
+ 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 sfEntries;
+ private byte[] sfBytes;
+ private HashUtils util;
+
+ // Constructor(s)
+ // --------------------------------------------------------------------------
+
+ /**
+ * @param jar the JAR archive the .SF file belongs to.
+ */
+ public SFHelper(JarFile jar)
+ {
+ super();
+
+ this.jar = jar;
+ this.state = READY;
+ }
+
+ // Class methods
+ // --------------------------------------------------------------------------
+
+ // Instance methods
+ // --------------------------------------------------------------------------
+
+ /**
+ * 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();
+ log.finest("\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$
+
+ log.finest("+++ 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);
+ log.finest("\n" + Util.dumpString(signedSFBytes, "+++ signedSFBytes ")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Set digestAlgorithms = new HashSet();
+ List digestAlgorithm = new ArrayList(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 signerInfos = new HashSet();
+ X509Certificate cert = (X509Certificate) certificates[0];
+ 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;
+ }
+
+ // own methods --------------------------------------------------------------
+
+ 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();
+ 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);
+ log.finer("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 = (Attributes) sfEntries.get(name);
+ if (sfAttributes == null)
+ {
+ sfAttributes = new Attributes();
+ sfEntries.put(name, sfAttributes);
+ }
+
+ sfAttributes.putValue(Main.DIGEST, sfHash);
+ log.finest("Name: " + name); //$NON-NLS-1$
+ log.finest(Main.DIGEST + ": " + sfHash); //$NON-NLS-1$
+ log.finest(""); //$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());
+ log.fine("Hashed Manifest " + manifestHash); //$NON-NLS-1$
+ sfMainAttributes.putValue(Main.DIGEST_MANIFEST, manifestHash);
+
+ this.state = FINISHED;
+ }
+}
diff --git a/tools/gnu/classpath/tools/jarsigner/jarsigner.txt b/tools/gnu/classpath/tools/jarsigner/jarsigner.txt
new file mode 100644
index 000000000..e615609c1
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/jarsigner.txt
@@ -0,0 +1,116 @@
+NAME
+ jarsigner - Java ARchive (JAR) file signing and verification tool
+
+SYNOPSIS
+ jarsigner [OPTION]... FILE ALIAS
+ jarsigner -verify [OPTION]... FILE
+
+DESCRIPTION
+ When the first form is used, the tool signs the designated JAR file.
+ The second form, on the other hand, is used to verify a previously
+ signed JAR file.
+
+ FILE is the .JAR file to process; i.e. to sign if the first syntax form
+ is used, or to verify if the second syntax form is used instead.
+
+ ALIAS must be a known Alias of a Key Entry in the designated key store.
+ The private key material associated with this Alias is then used for
+ signing the designated .JAR file.
+
+SIGNING OPTIONS
+ -keystore URL
+ Use this option to specify the location of the key store to use.
+ The default value is a file URL referencing the file named
+ ".keystore" (all lower case and without the enclosing quotes)
+ located in the path returned by the call to
+ java.lang.System#getProperty(String) using "user.home" as
+ argument.
+
+ 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 "file:".
+
+ -storetype STORE_TYPE
+ 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 "keystore.type" in the security properties file, which
+ is obtained by invoking the static method call getDefaultType()
+ in java.security.KeyStore.
+
+ -storepass PASSWORD
+ Use this option to specify the password which will be used to
+ unlock the key store. If this option is missing, the User will
+ be prompted to provide a password.
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -sigfile NAME
+ Use this option to designate a literal that will be used to
+ construct file names for both the .SF and .DSA signature files.
+ These files will be generated, by the tool, and placed in the
+ META-INF directory of the signed JAR. Permissible characters
+ for NAME must be in the range "a-zA-Z0-9_-". All characters
+ will be converted to upper-case ones.
+
+ If this option is missing, the first eight characters of the
+ ALIAS argument will be used. When this is the case, any
+ character in ALIAS that is outside the permissible range of
+ characters will be replaced by an underscore.
+
+ -signedjar FILE_NAME
+ Use this option to specify the file name of the signed JAR. If
+ this option is omitted, then the signed JAR will be named the
+ same as FILE; i.e. the input JAR file will be replaced with the
+ signed copy.
+
+VERIFICATION OPTIONS
+ -verify
+ Use this option to indicate that the tool is to be used for
+ verification purposes.
+
+ -certs This option is used in conjunction with the -verbose option.
+ When present, along with the -verbose option, the tool will
+ print more detailed information about the certificates of the
+ signer(s) being processed.
+
+COMMON OPTIONS
+ -verbose
+ Use this option to force the tool to generate more verbose
+ messages, during its processing.
+
+ -internalsf
+ When present, the tool will include --which otherwise it does
+ not-- the .SF file in the .DSA generated file.
+
+ -sectionsonly
+ When present, the tool will include in the .SF generated file
+ --which otherwise it does not-- a header containing a hash of
+ the whole manifest file. When that header is included, the
+ tool can quickly check, during verification, if the hash (in
+ the header) matches or not the manifest file.
+
+ -provider PROVIDER_CLASS_NAME
+ 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 remove this
+ Security Provider before exiting.
+
+ -help Prints this help text.
+
+REPORTING BUGS
+ Please report bugs at http://www.gnu.org/software/classpath/bugs.html
+
+COPYRIGHT
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This is free software; see the source for copying conditions. There is
+ NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.
diff --git a/tools/gnu/classpath/tools/jarsigner/package.html b/tools/gnu/classpath/tools/jarsigner/package.html
new file mode 100644
index 000000000..50574ddb7
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/package.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.classpath.tools.jarsigner
+
+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. -->
+
+<html>
+<head>
+ <title>GNU Classpath - gnu.classpath.tools.jarsigner</title>
+</head>
+
+<body>
+This package contains the classes that provide an implementation of the
+Security Tool: <code>jarsigner</code>. The behaviour of these classes should
+match that of the same tool provided in the RI version 1.4.2, except for the
+following:
+
+<ul>
+ <li>The RI tool accepts -J<i>javaoption</i> options which it then passes to
+ the underlying JVM. This is because the RI tool acts as a <i>wrapper</i>
+ around the JVM launcher.
+ <p>
+ This implementation DOES NOT support these options.
+ </li>
+</ul>
+</body>
+</html>
diff --git a/tools/gnu/classpath/tools/keytool/CertReqCmd.java b/tools/gnu/classpath/tools/keytool/CertReqCmd.java
new file mode 100644
index 000000000..0c64246e8
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/CertReqCmd.java
@@ -0,0 +1,405 @@
+/* CertReqCmd.java -- The certreq 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.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.security.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_TYP}</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 String _alias;
+ private String _sigAlgorithm;
+ private String _certReqFileName;
+ private String _password;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM //$NON-NLS-1$
+ _sigAlgorithm = args[++i];
+ else if ("-file".equals(opt)) // -file FILE_NAME //$NON-NLS-1$
+ _certReqFileName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else if ("-attributes".equals(opt)) //$NON-NLS-1$
+ nullAttributes = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(_certReqFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+// setSignatureAlgorithm(_sigAlgorithm);
+
+ log.finer("-certreq handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -sigalg=" + _sigAlgorithm); //$NON-NLS-1$
+ log.finer(" -file=" + _certReqFileName); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ log.finer(" -attributes=" + nullAttributes); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ InvalidKeyException, SignatureException
+ {
+ 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, 0, derBytes.length, true);
+ 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();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * @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/tools/gnu/classpath/tools/keytool/Command.java b/tools/gnu/classpath/tools/keytool/Command.java
new file mode 100644
index 000000000..a59614644
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/Command.java
@@ -0,0 +1,1147 @@
+/* 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.SystemProperties;
+import gnu.classpath.tools.common.CallbackUtil;
+import gnu.classpath.tools.common.ProviderUtil;
+import gnu.classpath.tools.common.SecurityProviderInfo;
+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 gnu.javax.security.auth.callback.ConsoleCallbackHandler;
+
+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;
+
+ // Constructor(s) -----------------------------------------------------------
+
+ // default 0-arguments constructor
+
+ // 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();
+ }
+ }
+
+ /**
+ * @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.
+ * @param startIndex the index of the first argument in <code>args</code> to
+ * process.
+ * @return the index of the first unprocessed argument in <code>args</code>.
+ */
+ abstract int processArgs(String[] args, int startIndex);
+
+ /**
+ * 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()
+ {
+ log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+
+ if (storeStream != null)
+ try
+ {
+ storeStream.close();
+ }
+ catch (IOException ignored)
+ {
+ 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());
+
+ log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ }
+
+ // parameter setup and validation methods -----------------------------------
+
+ /**
+ * Convenience method to setup the key store given its type, its password, its
+ * location and portentially a specialized security provider.
+ *
+ * @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
+ {
+ setProviderClassNameParam(className);
+ setKeystoreTypeParam(type);
+ setKeystorePasswordParam(password);
+ setKeystoreURLParam(url);
+ }
+
+ /**
+ * 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.
+ */
+ protected void setProviderClassNameParam(String className)
+ {
+ log.finest("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)
+ 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.
+ */
+ protected void setKeystoreTypeParam(String type)
+ {
+ log.finest("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.
+ */
+ protected 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$
+ }
+
+ protected 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();
+ }
+ log.finest("storePasswordChars = [" + String.valueOf(storePasswordChars)+ "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Set the key store URL to use.
+ *
+ * @param url
+ * @throws IOException
+ * @throws KeyStoreException
+ * @throws UnsupportedCallbackException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ */
+ protected void setKeystoreURLParam(String url) throws IOException,
+ KeyStoreException, UnsupportedCallbackException, NoSuchAlgorithmException,
+ CertificateException
+ {
+ log.finest("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
+ 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$
+ new File(url).createNewFile();
+
+ url = "file:" + url; //$NON-NLS-1$
+ }
+
+ boolean newKeyStore = false;
+ storeURL = new URL(url);
+ storeStream = storeURL.openStream();
+ if (storeStream.available() == 0)
+ {
+ 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;
+
+ 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);
+ }
+
+ // 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)
+ {
+ 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
+ {
+ 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();
+
+ 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
+ {
+ log.entering(this.getClass().getName(), "saveKeyStore", String.valueOf(password)); //$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();
+
+ 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 ConsoleCallbackHandler}.
+ *
+ * @return a console-based {@link CallbackHandler}.
+ */
+ protected CallbackHandler getCallbackHandler()
+ {
+ if (handler == null)
+ handler = CallbackUtil.getConsoleHandler();
+
+ return handler;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/DeleteCmd.java b/tools/gnu/classpath/tools/keytool/DeleteCmd.java
new file mode 100644
index 000000000..968af50f8
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/DeleteCmd.java
@@ -0,0 +1,235 @@
+/* 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 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_TYP}</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());
+ private String _alias;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setTheAlias(_alias);
+
+ log.finer("-delete handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ CertificateException, IOException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ ensureStoreContainsAlias();
+ store.deleteEntry(alias);
+ saveKeyStore();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * 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/tools/gnu/classpath/tools/keytool/ExportCmd.java b/tools/gnu/classpath/tools/keytool/ExportCmd.java
new file mode 100644
index 000000000..c1c0d4f83
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/ExportCmd.java
@@ -0,0 +1,266 @@
+/* ExportCmd.java -- The export 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.java.security.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_TYP}</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());
+ private String _alias;
+ private String _certFileName;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS
+ _alias = args[++i];
+ else if ("-file".equals(opt)) // -file FILE_NAME
+ _certFileName = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME
+ _providerClassName = args[++i];
+ else if ("-rfc".equals(opt))
+ rfc = true;
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(_certFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+
+ log.finer("-export handler will use the following options:");
+ log.finer(" -alias=" + alias);
+ log.finer(" -file=" + _certFileName);
+ log.finer(" -storetype=" + storeType);
+ log.finer(" -keystore=" + storeURL);
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars));
+ log.finer(" -provider=" + provider);
+ log.finer(" -rfc=" + rfc);
+ log.finer(" -v=" + verbose);
+ }
+
+ void start() throws KeyStoreException, CertificateEncodingException,
+ IOException
+ {
+ log.entering(this.getClass().getName(), "start");
+
+ ensureStoreContainsAlias();
+ Certificate certificate;
+ if (store.isCertificateEntry(alias))
+ {
+ log.fine("Alias [" + alias + "] is a trusted certificate");
+ certificate = store.getCertificate(alias);
+ }
+ else
+ {
+ log.fine("Alias [" + alias + "] is a key entry");
+ Certificate[] chain = store.getCertificateChain(alias);
+ certificate = chain[0];
+ }
+
+ byte[] derBytes = certificate.getEncoded();
+ if (rfc)
+ {
+ String encoded = Base64.encode(derBytes, 0, derBytes.length, true);
+ PrintWriter pw = new PrintWriter(outStream, true);
+ pw.println("-----BEGIN CERTIFICATE-----");
+ pw.println(encoded);
+ pw.println("-----END CERTIFICATE-----");
+ }
+ else
+ outStream.write(derBytes);
+
+ // stream is closed in Command.teardown()
+ log.exiting(this.getClass().getName(), "start");
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/GenKeyCmd.java b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java
new file mode 100644
index 000000000..2d92134c2
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java
@@ -0,0 +1,511 @@
+/* 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.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_TYP}</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;
+
+ private String _alias;
+ private String _keyAlgorithm;
+ private String _keySizeStr;
+ private String _sigAlgorithm;
+ private String _dName;
+ private String _password;
+ private String _validityStr;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-keyalg".equals(opt)) // -keyalg ALGORITHM //$NON-NLS-1$
+ _keyAlgorithm = args[++i];
+ else if ("-keysize".equals(opt)) // -keysize KEY_SIZE //$NON-NLS-1$
+ _keySizeStr = args[++i];
+ else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM //$NON-NLS-1$
+ _sigAlgorithm = args[++i];
+ else if ("-dname".equals(opt)) // -dname NAME //$NON-NLS-1$
+ _dName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-validity".equals(opt)) // -validity DAY_COUNT //$NON-NLS-1$
+ _validityStr = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordParam(_password);
+ setAlgorithmParams(_keyAlgorithm, _sigAlgorithm);
+ setKeySize(_keySizeStr);
+ setDName(_dName);
+ setValidityParam(_validityStr);
+
+ log.finer("-genkey handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -keyalg=" + keyPairGenerator.getAlgorithm()); //$NON-NLS-1$
+ log.finer(" -keysize=" + keySize); //$NON-NLS-1$
+ log.finer(" -sigalg=" + signatureAlgorithm.getAlgorithm()); //$NON-NLS-1$
+ log.finer(" -dname=" + distinguishedName); //$NON-NLS-1$
+ log.finer(" -keypass=" + String.valueOf(keyPasswordChars)); //$NON-NLS-1$
+ log.finer(" -validity=" + validityInDays); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws CertificateException, KeyStoreException,
+ InvalidKeyException, SignatureException, IOException,
+ NoSuchAlgorithmException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ // 1. generate a new key-pair
+ log.fine("About to generate key-pair...");
+ keyPairGenerator.initialize(keySize);
+ KeyPair kp = keyPairGenerator.generateKeyPair();
+ PublicKey publicKey = kp.getPublic();
+ PrivateKey privateKey = kp.getPrivate();
+
+ // 2. generate a self-signed certificate
+ log.fine("About to generate a self-signed certificate...");
+ byte[] derBytes = getSelfSignedCertificate(distinguishedName,
+ publicKey,
+ privateKey);
+ log.finest(Util.dumpString(derBytes, "derBytes ")); //$NON-NLS-1$
+ CertificateFactory x509Factory = CertificateFactory.getInstance(Main.X_509);
+ ByteArrayInputStream bais = new ByteArrayInputStream(derBytes);
+ Certificate certificate = x509Factory.generateCertificate(bais);
+ log.finest("certificate = " + certificate); //$NON-NLS-1$
+
+ // 3. store it, w/ its private key, associating them to alias
+ Certificate[] chain = new Certificate[] { certificate };
+ log.finest("About to store newly generated material in key store..."); //$NON-NLS-1$
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, chain);
+
+ // 4. persist the key store
+ saveKeyStore();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * @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();
+ }
+
+ 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/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java b/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java
new file mode 100644
index 000000000..cb6b6dac2
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java
@@ -0,0 +1,185 @@
+/* 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 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_TYP}</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());
+ private String _idbFileName;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-file".equals(opt)) // -file FILE_NAME
+ _idbFileName = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_idbFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+
+ log.finer("-identitydb handler will use the following options:");
+ log.finer(" -file=" + _idbFileName);
+ log.finer(" -storetype=" + storeType);
+ log.finer(" -keystore=" + storeURL);
+ log.finer(" -storepass=" + new String(storePasswordChars));
+ log.finer(" -provider=" + provider);
+ log.finer(" -v=" + verbose);
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/ImportCmd.java b/tools/gnu/classpath/tools/keytool/ImportCmd.java
new file mode 100644
index 000000000..b5058b581
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/ImportCmd.java
@@ -0,0 +1,751 @@
+/* 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.SystemProperties;
+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.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.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collection;
+import java.util.LinkedList;
+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_TYP}</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 String _alias;
+ private String _certFileName;
+ private String _password;
+ private boolean noPrompt;
+ private boolean trustCACerts;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private CertificateFactory x509Factory;
+ private boolean imported;
+
+ // 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-file".equals(opt)) // -file FILE_NAME //$NON-NLS-1$
+ _certFileName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-noprompt".equals(opt)) //$NON-NLS-1$
+ noPrompt = true;
+ else if ("-trustcacerts".equals(opt)) //$NON-NLS-1$
+ trustCACerts = true;
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_certFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+
+ log.finer("-import handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -file=" + _certFileName); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -noprompt=" + noPrompt); //$NON-NLS-1$
+ log.finer(" -trustcacerts=" + trustCACerts); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws CertificateException, KeyStoreException, IOException,
+ UnsupportedCallbackException, NoSuchAlgorithmException,
+ CertPathValidatorException, UnrecoverableKeyException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ 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();
+ }
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * 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
+ {
+ log.entering(this.getClass().getName(), "importNewTrustedCertificate"); //$NON-NLS-1$
+
+ Certificate certificate = x509Factory.generateCertificate(inStream);
+ log.finest("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$
+
+ 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
+ {
+ 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);
+
+ 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
+ {
+ 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();
+
+ 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
+ {
+ 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();
+ }
+
+ 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
+ {
+ log.entering(this.getClass().getName(), "ensureReplyIsOurs"); //$NON-NLS-1$
+
+ Certificate certificate = (Certificate) certificates.iterator().next();
+ log.finest("certificate = " + certificate); //$NON-NLS-1$
+ Certificate[] chain = store.getCertificateChain(alias);
+ if (chain == null)
+ throw new IllegalArgumentException(Messages.getFormattedString("ImportCmd.37", //$NON-NLS-1$
+ alias));
+ Certificate anchor = chain[0];
+ PublicKey anchorPublicKey = anchor.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$
+
+ 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;
+ }
+
+ /**
+ * @param chain
+ * @return the input collection, ordered with own certificate first, and CA's
+ * self-signed certificate last.
+ */
+ private LinkedList orderChain(Collection chain)
+ {
+ log.entering(this.getClass().getName(), "orderChain"); //$NON-NLS-1$
+
+ LinkedList result = new LinkedList();
+
+
+ log.entering(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
+ {
+ log.entering(this.getClass().getName(), "findTrustAndUpdate"); //$NON-NLS-1$
+
+ X509CertPath certPath = new X509CertPath(reply);
+ CertPathValidator validator = CertPathValidator.getInstance("PKIX"); //$NON-NLS-1$
+ PKIXCertPathValidatorResult cpvr = findTrustInStore(certPath, validator);
+ if (cpvr == null && trustCACerts)
+ cpvr = findTrustInCACerts(certPath, validator);
+
+ 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
+ {
+ log.fine("Found a chain-of-trust anchored by " + cpvr.getTrustAnchor()); //$NON-NLS-1$
+ Certificate trustedCert = cpvr.getTrustAnchor().getTrustedCert();
+ reply.addLast(trustedCert);
+ result = true;
+ }
+
+ log.entering(this.getClass().getName(), "findTrustAndUpdate", //$NON-NLS-1$
+ Boolean.valueOf(result));
+ return result;
+ }
+
+ private PKIXCertPathValidatorResult findTrustInStore(X509CertPath certPath,
+ CertPathValidator validator)
+ {
+ 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;
+ }
+
+ log.exiting(this.getClass().getName(), "findTrustInStore", result); //$NON-NLS-1$
+ return result;
+ }
+
+ private PKIXCertPathValidatorResult findTrustInCACerts(X509CertPath certPath,
+ CertPathValidator validator)
+ {
+ log.entering(this.getClass().getName(), "findTrustInCACerts"); //$NON-NLS-1$
+
+ FileInputStream stream = null;
+ PKIXCertPathValidatorResult result = null;
+ try
+ {
+ KeyStore cacerts = KeyStore.getInstance("jks"); //$NON-NLS-1$
+ String cacertsPath = SystemProperties.getProperty("java.home");
+ String fs = SystemProperties.getProperty("file.separator"); //$NON-NLS-1$
+ cacertsPath = new StringBuilder(cacertsPath).append(fs)
+ .append("lib").append(fs) //$NON-NLS-1$
+ .append("security").append(fs) //$NON-NLS-1$
+ .append("cacerts").toString(); //$NON-NLS-1$
+ stream = new FileInputStream(cacertsPath);
+ cacerts.load(stream, "changeit".toCharArray()); //$NON-NLS-1$
+ PKIXParameters params = new PKIXParameters(cacerts);
+ result = (PKIXCertPathValidatorResult) validator.validate(certPath,
+ params);
+ }
+ catch (Exception x)
+ {
+ log.log(Level.FINE,
+ "Exception in findTrustInCACerts(). Ignore + Return NULL", //$NON-NLS-1$
+ x);
+ }
+ finally
+ {
+ if (stream != null)
+ try
+ {
+ stream.close();
+ }
+ catch (Exception ignored)
+ {
+ }
+ }
+
+ log.exiting(this.getClass().getName(), "findTrustInCACerts", result); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java b/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java
new file mode 100644
index 000000000..5936719f7
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java
@@ -0,0 +1,344 @@
+/* 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 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_TYP}</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());
+ private String _alias;
+ private String _destAlias;
+ private String _password;
+ private String _newPassword;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-dest".equals(opt)) // -dest ALIAS //$NON-NLS-1$
+ _destAlias = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$
+ _newPassword = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+ setDestinationAlias(_destAlias);
+// setNewKeyPassword(_newPassword);
+
+ log.finer("-keyclone handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -dest=" + destinationAlias); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -new=" + _newPassword); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ CertificateException
+ {
+ 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();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ 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) // ask user to provide one
+ newKeyPasswordChars = 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
+ {
+ 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/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java b/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java
new file mode 100644
index 000000000..9dc7b8164
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java
@@ -0,0 +1,339 @@
+/* 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.SystemProperties;
+
+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_TYP}</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());
+ private String _alias;
+ private String _password;
+ private String _newPassword;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$
+ _newPassword = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+// setNewKeyPassword(_newPassword);
+
+ log.finer("-keypasswd handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -new=" + _newPassword); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ CertificateException
+ {
+ 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();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * 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/tools/gnu/classpath/tools/keytool/ListCmd.java b/tools/gnu/classpath/tools/keytool/ListCmd.java
new file mode 100644
index 000000000..655242785
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/ListCmd.java
@@ -0,0 +1,380 @@
+/* ListCmd.java -- The list 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.java.security.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_TYP}</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());
+ private String _alias;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else if ("-rfc".equals(opt)) //$NON-NLS-1$
+ rfc = true;
+ else
+ break;
+ }
+
+ all = _alias == null;
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(null); // use stdout
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ if (! all)
+ setAliasParam(_alias);
+
+ if (verbose & rfc)
+ {
+ log.warning("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;
+ }
+
+ log.finer("-list handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ log.finer(" -rfc=" + rfc); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, CertificateEncodingException,
+ IOException
+ {
+ 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)
+ {
+ log.finest("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);
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * 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
+ {
+ 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", store.getCreationDate(anAlias))); //$NON-NLS-1$
+
+ 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));
+ 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, 0, derBytes.length, true);
+ 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/tools/gnu/classpath/tools/keytool/Main.java b/tools/gnu/classpath/tools/keytool/Main.java
new file mode 100644
index 000000000..fb7aa4509
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/Main.java
@@ -0,0 +1,219 @@
+/* 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.tools.HelpPrinter;
+import gnu.classpath.tools.common.ProviderUtil;
+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());
+ /** The relative file path to the command tool's help text. */
+ private static final String HELP_PATH = "keytool/keytool.txt"; //$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;
+
+ private Main()
+ {
+ super();
+ }
+
+ public static final void main(String[] args)
+ {
+ log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$
+
+ Main tool = new Main();
+ try
+ {
+ tool.setup();
+ tool.start(args);
+ }
+ catch (SecurityException x)
+ {
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getString("Main.6") + x.getMessage()); //$NON-NLS-1$
+ }
+ catch (Exception x)
+ {
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getString("Main.8") + x); //$NON-NLS-1$
+ }
+ finally
+ {
+ tool.teardown();
+ }
+
+ log.exiting(Main.class.getName(), "main"); //$NON-NLS-1$
+ // System.exit(0);
+ }
+
+ // helper methods -----------------------------------------------------------
+
+ private void start(String[] args) throws Exception
+ {
+ log.entering(this.getClass().getName(), "start", args); //$NON-NLS-1$
+
+ if (args == null)
+ args = new String[0];
+
+ int limit = args.length;
+ log.finest("args.length=" + limit); //$NON-NLS-1$
+ int i = 0;
+ String opt;
+ Command cmd;
+ while (i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ cmd = null;
+ if ("-genkey".equals(opt)) //$NON-NLS-1$
+ cmd = new GenKeyCmd();
+ else if ("-import".equals(opt)) //$NON-NLS-1$
+ cmd = new ImportCmd();
+ else if ("-selfcert".equals(opt)) //$NON-NLS-1$
+ cmd = new SelfCertCmd();
+ else if ("-identitydb".equals(opt)) //$NON-NLS-1$
+ cmd = new IdentityDBCmd();
+ else if ("-certreq".equals(opt)) //$NON-NLS-1$
+ cmd = new CertReqCmd();
+ else if ("-export".equals(opt)) //$NON-NLS-1$
+ cmd = new ExportCmd();
+ else if ("-list".equals(opt)) //$NON-NLS-1$
+ cmd = new ListCmd();
+ else if ("-printcert".equals(opt)) //$NON-NLS-1$
+ cmd = new PrintCertCmd();
+ else if ("-keyclone".equals(opt)) //$NON-NLS-1$
+ cmd = new KeyCloneCmd();
+ else if ("-storepasswd".equals(opt)) //$NON-NLS-1$
+ cmd = new StorePasswdCmd();
+ else if ("-keypasswd".equals(opt)) //$NON-NLS-1$
+ cmd = new KeyPasswdCmd();
+ else if ("-delete".equals(opt)) //$NON-NLS-1$
+ cmd = new DeleteCmd();
+ else if ("-help".equals(opt)) //$NON-NLS-1$
+ {
+ printHelp();
+ i++;
+ }
+ else
+ {
+ log.fine("Unknown command [" + opt + "] at index #" + i //$NON-NLS-1$ //$NON-NLS-2$
+ + ". Arguments from that token onward will be ignored"); //$NON-NLS-1$
+ break;
+ }
+
+ if (cmd != null)
+ {
+ i = cmd.processArgs(args, i);
+ cmd.doCommand();
+ }
+ }
+
+ // the -help command is the default; i.e.
+ // keytool
+ // is equivalent to:
+ // keytool -help
+ if (i == 0)
+ printHelp();
+
+ if (i < limit) // more options than needed
+ log.fine("Last recognized argument is assumed at index #" + (i - 1) //$NON-NLS-1$
+ + ". Remaining arguments (" + args[i] + "...) will be ignored"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ private void setup()
+ {
+ log.entering(this.getClass().getName(), "setup"); //$NON-NLS-1$
+
+ gnuCryptoProviderNdx = ProviderUtil.addProvider(new GnuCrypto());
+ gnuCallbacksNdx = ProviderUtil.addProvider(new GnuCallbacks());
+
+ log.exiting(this.getClass().getName(), "setup"); //$NON-NLS-1$
+ }
+
+ private void teardown()
+ {
+ 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$
+
+ log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ }
+
+ private void printHelp()
+ {
+ if (helpPrinted)
+ return;
+
+ HelpPrinter.printHelp(HELP_PATH);
+ helpPrinted = true;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/Messages.java b/tools/gnu/classpath/tools/keytool/Messages.java
new file mode 100644
index 000000000..e3308e021
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/Messages.java
@@ -0,0 +1,115 @@
+/* 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 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.MessageBundle"; //$NON-NLS-1$
+ 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 consisiting 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)
+ {
+ 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/tools/gnu/classpath/tools/keytool/PrintCertCmd.java b/tools/gnu/classpath/tools/keytool/PrintCertCmd.java
new file mode 100644
index 000000000..9ba1d5970
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/PrintCertCmd.java
@@ -0,0 +1,123 @@
+/* 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 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());
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-file".equals(opt)) // -file FILE_NAME
+ _certFileName = args[++i];
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_certFileName);
+
+ log.finer("-printcert handler will use the following options:");
+ log.finer(" -file=" + _certFileName);
+ log.finer(" -v=" + verbose);
+ }
+
+ void start() throws CertificateException
+ {
+ log.entering(getClass().getName(), "start");
+
+ CertificateFactory x509Factory = CertificateFactory.getInstance(Main.X_509);
+ Certificate certificate = x509Factory.generateCertificate(inStream);
+ PrintWriter writer = new PrintWriter(System.out, true);
+ writer.println();
+ printVerbose(certificate, writer);
+
+ log.exiting(getClass().getName(), "start");
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/SelfCertCmd.java b/tools/gnu/classpath/tools/keytool/SelfCertCmd.java
new file mode 100644
index 000000000..db7d45994
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/SelfCertCmd.java
@@ -0,0 +1,371 @@
+/* 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.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_TYP}</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());
+ private String _alias;
+ private String _sigAlgorithm;
+ private String _dName;
+ private String _password;
+ private String _validityStr;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS
+ _alias = args[++i];
+ else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM
+ _sigAlgorithm = args[++i];
+ else if ("-dname".equals(opt)) // -dname NAME
+ _dName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD
+ _password = args[++i];
+ else if ("-validity".equals(opt)) // -validity DAY_COUNT
+ _validityStr = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+// setDName(_dName);
+ setValidityParam(_validityStr);
+// setSignatureAlgorithm(_sigAlgorithm);
+
+ log.finer("-selfcert handler will use the following options:");
+ log.finer(" -alias=" + alias);
+ log.finer(" -sigalg=" + _sigAlgorithm);
+ log.finer(" -dname=" + _dName);
+ log.finer(" -keypass=" + _password);
+ log.finer(" -validity=" + validityInDays);
+ log.finer(" -storetype=" + storeType);
+ log.finer(" -keystore=" + storeURL);
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars));
+ log.finer(" -provider=" + provider);
+ log.finer(" -v=" + verbose);
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException, IOException, UnsupportedCallbackException,
+ InvalidKeyException, SignatureException, CertificateException
+ {
+ log.entering(getClass().getName(), "start");
+
+ // 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");
+ 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();
+
+ log.exiting(getClass().getName(), "start");
+ }
+
+ // own methods --------------------------------------------------------------
+
+ 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/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java b/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java
new file mode 100644
index 000000000..1eb053c1c
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java
@@ -0,0 +1,275 @@
+/* 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.SystemProperties;
+
+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_TYP}</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());
+ private String _newPassword;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private 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 -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$
+ _newPassword = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setNewKeystorePassword(_newPassword);
+
+ log.finer("-storepasswd handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -new=" + String.valueOf(newStorePasswordChars)); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ CertificateException, IOException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ saveKeyStore(newStorePasswordChars);
+
+ log.exiting(getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ 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/tools/gnu/classpath/tools/keytool/keytool.txt b/tools/gnu/classpath/tools/keytool/keytool.txt
new file mode 100644
index 000000000..15f9b96f9
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/keytool.txt
@@ -0,0 +1,616 @@
+NAME
+ keytool - manage private keys and public certificates
+
+SYNOPSIS
+ keytool [COMMAND]...
+
+DESCRIPTION
+ A Java-based tool for managing both Key Entries as well as Trusted
+ Certificates.
+
+ Multiple COMMANDs may be specified at once, each complete with its own
+ options. keytool will parse all the arguments, before processing, and
+ executing, each COMMAND. If an exception occurs while executing one
+ COMMAND keytool will abort.
+
+ A COMMAND can be one of the followings:
+
+ -genkey [OPTION]...
+ Generate a new Key Entry, eventually creating a new key store.
+
+ -import [OPTION]...
+ Add, to a key store, Key Entries (private keys and certificate
+ chains authenticating the public keys) and Trusted Certificates
+ (3rd party certificates which can be used as Trust anchors when
+ building chains-of-trust).
+
+ -selfcert [OPTION]...
+ Generate a new self-signed Trusted Certificate.
+
+ -identitydb [OPTION]...
+ NOT IMPLEMENTED YET.
+ Import a JDK 1.1 style Identity Database.
+
+ -certreq [OPTION]...
+ Issue a Certificate Signing Request (CSR) which can be then sent
+ to a Certification Authority (CA) to issue a certificate signed
+ (by the CA) and authenticating the Subject of the request.
+
+ -export [OPTION]...
+ Export a Certificate from a key store.
+
+ -list [OPTION]...
+ Print one or all Certificates in a key store to STDOUT.
+
+ -printcert [OPTION]...
+ Print a human-readable form of a Certificate in a designated
+ file to STDOUT.
+
+ -keyclone [OPTION]...
+ Clone a Key Entry in a key store.
+
+ -storepasswd [OPTION]...
+ Change the password protecting a key store.
+
+ -keypasswd [OPTION]...
+ Change the password protecting a Key Entry in a key store.
+
+ -delete [OPTION]...
+ Delete a Key Entry or a Trusted Certificate from a key store.
+
+ -help Display this text.
+
+OPTIONS COMMON TO MORE THAN ONE COMMAND
+ The following OPTIONs are used in more than one COMMAND. They are
+ described here to reduce redundancy.
+
+ -alias ALIAS
+ Every entry, be it a Key Entry or a Trusted Certificate, in a
+ key store is uniquely identified by a user-defined Alias string.
+ Use this option to specify the Alias to use when referring to an
+ entry in the key store. Unless specified otherwise, a default
+ value of "mykey" (all lower case, without the enclosing quotes)
+ shall be used when this option is omitted from the command line.
+
+ -keyalg ALGORITHM
+ Use this option to specify the canonical name of the key-pair
+ generation algorithm. The default value for this option is
+ "DSS" (a synonym for the Digital Signature Algorithm also known
+ as DSA).
+
+ -keysize SIZE
+ 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 1024 will be used if
+ this option is omitted from the command line.
+
+ -validity DAY_COUNT
+ Use this option to specify the number of days a newly generated
+ certificate will be valid for. The default value is 90 (days)
+ if this option is omitted from the command line.
+
+ -storetype STORE_TYPE
+ 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 "keystore.type" in the security properties file, which
+ is obtained by invoking the static method call getDefaultType()
+ in java.security.KeyStore.
+
+ -storepass PASSWORD
+ 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.
+
+ -keystore URL
+ Use this option to specify the location of the key store to use.
+ The default value is a file URL referencing the file named
+ ".keystore" (all lower case and without the enclosing quotes)
+ located in the path returned by the call to
+ java.lang.System#getProperty(String) using "user.home" as
+ argument.
+
+ 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 "file:".
+
+ -provider PROVIDER_CLASS_NAME
+ 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 remove this
+ Security Provider before exiting.
+
+ -file FILE_NAME
+ Use this option to designate a file to use with a command. When
+ specified with this option, the value is expected to be the
+ fully qualified path of a file accessible by the File System.
+ Depending on the command, the file may be used as input or as
+ output. When this option is omitted from the command line,
+ STDIN will be used instead, as the source of input, and STDOUT
+ will be used instead as the output destination.
+
+ -v Unless specified otherwise, use this option to enable more
+ verbose output.
+
+X.500 DISTINGUISHED NAME
+ A Distinguished Name (or DN) MUST be supplied with some of the COMMANDs
+ using a -dname option. 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:
+
+ CN The Common Name; e.g. "host.domain.com"
+ OU The Organizational Unit; e.g. "IT Department"
+ O The Organization Name; e.g. "The Sample Company"
+ L The Locality Name; e.g. "Sydney"
+ ST The State Name; e.g. "New South Wales"
+ C The 2-letter Country identifier; e.g. "AU"
+
+ When specified with a -dname 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:
+
+ CN=host.domain.com, O=The Sample Company, L=Sydney, ST=NSW, C=AU
+
+ If the Distinguished Name is required, and no valid default value can be
+ used, the tool will prompt you to enter the information through the
+ console.
+
+-genkey COMMAND
+ Generate a new key-pair (both private and public keys), and save these
+ credentials in the key store as a Key Entry, associated with the
+ designated (if was specified in the -alias option) or default (if the
+ -alias option is omitted) Alias.
+
+ The private key material will be protected with a user-defined password
+ (see -keypass option). The public key on the other hand will be part
+ of a self-signed X.509 certificate, which will form a 1-element chain
+ and will be saved in the key store.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keyalg ALGORITHM
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keysize KEY_SIZE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -sigalg ALGORITHM
+ 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 -keyalg option. If the
+ key-pair generation algorithm is "DSA", the value for the
+ signature algorithm will be "SHA1withDSA". If on the other hand
+ the key-pair generation algorithm is "RSA", then the tool will
+ use "MD5withRSA" as the signature algorithm.
+
+ -dname NAME
+ This a mandatory value for the command. If no value is
+ specified --i.e. the -dname option is omitted-- the tool will
+ prompt you to enter a Distinguished Name to use as both the
+ Owner and Issuer of the generated self-signed certificate.
+
+ (see X.500 DISTINGUISHED NAME)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to protect the newly created Key Entry.
+
+ If this option is omitted, you will be prompted to provide a
+ password.
+
+ -validity DAY_COUNT
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-import COMMAND
+ Read an X.509 certificate, or a PKCS#7 Certificate Reply from a
+ designated input source and incorporate the certificates into the key
+ store.
+
+ If the Alias 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 Trusted Certificate, already stored in
+ the key store. If the -trustcacerts option is present, an additional
+ key store, of type "JKS" named "cacerts", and assumed to be present in
+ ${JAVA_HOME}/lib/security will also be consulted if found --${JAVA_HOME}
+ refers to the location of an installed Java Runtime Environment (JRE).
+ If no chain-of-trust can be established, and unless the -noprompt option
+ has been specified, the certificate is printed to STDOUT and the user is
+ prompted for a confirmation.
+
+ If Alias exists in the key store, the tool will treat the certificate(s)
+ read from the input source as a Certificate Reply, which can be a chain
+ of certificates, that eventually would replace the chain of certificates
+ associated with the Key Entry of that Alias. 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
+ Trusted Certificates already present in the key store. Again, if the
+ -trustcacerts option is specified, additional Trusted Certificates in
+ the same "cacerts" key store will be considered. If no chain-of-trust
+ can be established, the operation will abort.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to protect the Key Entry associated with the designated Alias,
+ when replacing this Alias' chain of certificates with that found
+ in the certificate reply.
+
+ 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 Key Entry using the same password
+ protecting the key store. If this fails, you will then be
+ prompted to provide a password.
+
+ -noprompt
+ Use this option to prevent the tool from prompting the user.
+
+ -trustcacerts
+ Use this option to indicate to the tool that a key store, of
+ type "JKS", named "cacerts", and usually located in lib/security
+ in an installed Java Runtime Environment should be considered
+ when trying to establish chain-of-trusts.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-selfcert COMMAND
+ Generate a self-signed X.509 version 1 certificate. The newly generated
+ certificate will form a chain of one element which will replace the
+ previous chain associated with the designated Alias (if -alias option
+ was specified), or the default Alias (if -alias option was omitted).
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -sigalg ALGORITHM
+ 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 Alias. If the private key is a
+ "DSA" one, the value for the signature algorithm will be
+ "SHA1withDSA". If on the other hand the private key is an "RSA"
+ one, then the tool will use "MD5withRSA" as the signature
+ algorithm.
+
+ -dname NAME
+ Use this option to specify the Distinguished Name of the newly
+ generated self-signed certificate. If this option is omitted,
+ the existing Distinguished Name of the base certificate in the
+ chain associated with the designated Alias will be used instead.
+
+ (see X.500 DISTINGUISHED NAME)
+
+ -validity DAY_COUNT
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-identitydb COMMAND
+ NOT IMPLEMENTED YET.
+
+ Import a JDK 1.1 style Identity Database.
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-certreq COMMAND
+ Generate a PKCS#10 Certificate Signing Request (CSR) and writes it to
+ a designated output destination. The contents of the destination
+ should look something like the following:
+
+ -----BEGIN NEW CERTIFICATE REQUEST-----
+ MIICYTCCAiECAQAwXzEUMBIGA1UEAwwLcnNuQGdudS5vcmcxGzAZBgNVBAoMElUg
+ Q29tcGFueTEPMA0GA1UEBwwGU3lkbmV5MQwwCgYDVQQIDANOU1cxCzAJBgNVBACC
+ ...
+ FCTlKlok8KwGuIVwNVOfQLRX+O5kAhQ/a4RTZme2L8PnpvgRwrf7Eg8D6w==
+ -----END NEW CERTIFICATE REQUEST-----
+
+ IMPORTANT: Some documentation (e.g. RSA examples) claims that the
+ Attributes field, in the CSR is OPTIONAL while RFC-2986 implies the
+ opposite. This implementation considers this field, by default, as
+ OPTIONAL, unless the option -attributes is specified on the command
+ line.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -sigalg ALGORITHM
+ 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 Alias. If the private key is a
+ "DSA" one, the value for the signature algorithm will be
+ "SHA1withDSA". If on the other hand the private key is an "RSA"
+ one, then the tool will use "MD5withRSA" as the signature
+ algorithm.
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -attributes
+ Use this option to force the tool to encode a NULL DER value in
+ the CSR as the value of the Attributes field.
+
+-export COMMAND
+ Export a certificate stored in the key store to a designated output
+ destination, either in binary format (if the -v option is specified),
+ or in RFC-1421 compliant encoding (if the -rfc option is specified
+ instead).
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -rfc Use RFC-1421 specifications when encoding the output.
+
+ -v Output the certificate in binary DER encoding. This is the
+ default output format of the command if neither -rfc nor -v
+ options were detected on the command line. If both this option
+ and the -rfc option are detected on the command line, the tool
+ will opt for the RFC-1421 style encoding.
+
+-list COMMAND
+ Print one or all of the key store entries to STDOUT. Usually this
+ command will only print a fingerprint of the certificate, unless either
+ the -rfc or the -v option is specified.
+
+ -alias ALIAS
+ If this option is omitted, the tool will print ALL the entries
+ found in the key store.
+
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -rfc Use RFC-1421 specifications when encoding the output.
+
+ -v Output the certificate in human-readable format. If both this
+ option and the -rfc option are detected on the command line,
+ the tool will opt for the human-readable form and will not
+ abort the command.
+
+-printcert COMMAND
+ Read a certificate from a designated input source and print it to STDOUT
+ in a human-readable form.
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-keyclone COMMAND
+ Clone an existing Key Entry and store it under a new (different) Alias
+ protecting, its private key material with possibly a new password.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -dest ALIAS
+ Use this option to specify the new Alias which will be used to
+ identify the cloned copy of the Key Entry.
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -new PASSWORD
+ Use this option to specify the password protecting the private
+ key material of the newly cloned copy of the Key Entry.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-storepasswd COMMAND
+ Change the password protecting a key store.
+
+ -new PASSWORD
+ The new, and different, password which will be used to protect
+ the designated key store.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-keypasswd COMMAND
+ Change the password protecting the private key material of a designated
+ Key Entry.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -new PASSWORD
+ The new, and different, password which will be used to protect
+ the private key material of the designated Key Entry.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-delete COMMAND
+ Delete a designated key store entry.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+REPORTING BUGS
+ Please report bugs at http://www.gnu.org/software/classpath/bugs.html
+
+COPYRIGHT
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This is free software; see the source for copying conditions. There is
+ NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.
diff --git a/tools/gnu/classpath/tools/keytool/package.html b/tools/gnu/classpath/tools/keytool/package.html
new file mode 100644
index 000000000..c447b8d01
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/package.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.classpath.tools.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. -->
+
+<html>
+<head>
+<title>GNU Classpath - gnu.classpath.tools.keytool</title>
+</head>
+
+<body>
+This package contains the classes that provide an implementation of the
+Security Tool: <code>keytool</code>. The behaviour of these classes should
+match that of the same tool provided in the RI version 1.4.2, except for the
+following:
+
+<ul>
+ <li>The RI tool accepts -J<i>javaoption</i> options which it then passes to
+ the underlying JVM. This is because the RI tool acts as a <i>wrapper</i>
+ around the JVM launcher.
+ <p>
+ This implementation DOES NOT support these options.
+ </li>
+
+ <li>The RI tool is capable of importing JDK-1.1 style <i>identities</i>.
+ <p>
+ This implementation does not offer this feature.
+ </li>
+</ul>
+</body>
+</html>
diff --git a/tools/gnu/classpath/tools/rmi/Persistent.java b/tools/gnu/classpath/tools/rmi/Persistent.java
new file mode 100644
index 000000000..5cd1efe91
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/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.rmi;
+
+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/tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java b/tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java
new file mode 100644
index 000000000..94b5bcbee
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java
@@ -0,0 +1,268 @@
+/* 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.rmi;
+
+import gnu.classpath.tools.rmi.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/tools/gnu/classpath/tools/rmi/PersistentHashTable.java b/tools/gnu/classpath/tools/rmi/PersistentHashTable.java
new file mode 100644
index 000000000..925e829ff
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/PersistentHashTable.java
@@ -0,0 +1,246 @@
+/* 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.rmi;
+
+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;
+ if (file.exists())
+ {
+ if (coldStart)
+ {
+ file.delete();
+ k2v = new PersistentHashTable(file);
+ }
+ else
+ {
+ FileInputStream fi = new FileInputStream(file);
+ BufferedInputStream b = new BufferedInputStream(fi);
+ ObjectInputStream oin = new ObjectInputStream(b);
+
+ k2v = (PersistentHashTable) oin.readObject();
+ oin.close();
+ }
+ }
+ else
+ k2v = new PersistentHashTable(file);
+
+ 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/tools/gnu/classpath/tools/rmi/REGISTRY.java b/tools/gnu/classpath/tools/rmi/REGISTRY.java
new file mode 100644
index 000000000..63f633f99
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/REGISTRY.java
@@ -0,0 +1,165 @@
+/* REGISTY.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.rmi;
+
+import gnu.classpath.tools.HelpPrinter;
+import gnu.classpath.tools.rmi.registry.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 REGISTRY
+{
+ /**
+ * 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;
+
+ /**
+ * The RMI registry implementation entry point.
+ */
+ public static void main(String[] args)
+ {
+ String HelpPath = "rmi/REGISTRY.txt";
+ HelpPrinter.checkHelpKey(args, HelpPath);
+
+ // Parse parameters:
+ String folder = ".";
+ boolean cold = false;
+ boolean trans = false;
+ boolean stop = false;
+
+ int port = Registry.REGISTRY_PORT;
+ RMIServerSocketFactory ssf = null;
+
+ for (int i = 0; i < args.length; i++)
+ {
+ String a = args[i];
+ if (a.equals("-restart"))
+ cold = true;
+ else if (a.equals("-transient"))
+ trans = true;
+ else if (a.equals("-verbose"))
+ verbose = true;
+ else if (a.equals("-stop"))
+ stop = true;
+ else if (i < args.length - 1)
+ {
+ // The additional key parameter is possible.
+ if (a.equals("-port"))
+ port = Integer.parseInt(args[++i]);
+ else if (a.equals("-folder"))
+ folder = args[++i];
+ }
+ }
+
+ if (!stop)
+ {
+ Map table;
+ if (trans)
+ table = new Hashtable();
+ else
+ {
+ // Start the system.
+ File dataFolder = new File(folder);
+ if (!dataFolder.exists())
+ dataFolder.mkdirs();
+ table = PersistentHashTable.createInstance(
+ new File(dataFolder, "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 "+
+ REGISTRY.class.getName());
+ }
+ }
+ }
+}
diff --git a/tools/gnu/classpath/tools/rmi/REGISTRY.txt b/tools/gnu/classpath/tools/rmi/REGISTRY.txt
new file mode 100644
index 000000000..7d8e19232
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/REGISTRY.txt
@@ -0,0 +1,28 @@
+The persistent RMI naming service, required for the remote method invocations
+(packages java.rmi.*, java.rmi.Registry.*).
+
+Copyright 2006 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+Please report bugs at http://www.gnu.org/software/classpath/bugs.html
+
+Usage: rmiregistry <options>
+
+ where <options> includes:
+ -port N Start the registry on the given local port. If this key
+ is not specified, the service starts on the port 1099.
+ -verbose Log binding events to stdout.
+ -stop Stop the running naming service at the given port.
+
+ -transient Start transient registry service that does not write any
+ data to the disk. Such service looses the stored bindings if
+ restarted. If this key is not specified, the
+ persistent naming service is started.
+ -restart "Cold start:, clear the persistent naming database, if any.
+ -folder Folder Store the persistent binding file in the given folder. If this
+ key is not specified, the file with persistent bindings is
+ stored into the current folder.
+
+
+
diff --git a/tools/gnu/classpath/tools/rmi/RMIC.java b/tools/gnu/classpath/tools/rmi/RMIC.java
index 09021dd3f..c44453011 100644
--- a/tools/gnu/classpath/tools/rmi/RMIC.java
+++ b/tools/gnu/classpath/tools/rmi/RMIC.java
@@ -17,30 +17,13 @@ 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.rmi;
import gnu.classpath.tools.HelpPrinter;
import gnu.classpath.tools.giop.GRMIC;
-import gnu.classpath.tools.giop.grmic.GiopRmicCompiler;
import gnu.classpath.tools.rmi.rmic.RmicCompiler;
import java.io.File;
@@ -114,6 +97,10 @@ public class RMIC
verbose = true;
compiler.setVerbose(true);
}
+ else if (c.equals("-force"))
+ {
+ compiler.setForce(true);
+ }
else if (c.equals("-d"))
{
int f = i + 1;
diff --git a/tools/gnu/classpath/tools/rmi/RMIC.txt b/tools/gnu/classpath/tools/rmi/RMIC.txt
index df1de9ea6..7ec371e9a 100644
--- a/tools/gnu/classpath/tools/rmi/RMIC.txt
+++ b/tools/gnu/classpath/tools/rmi/RMIC.txt
@@ -16,6 +16,8 @@ Usage: rmic <options> <class names>
-help Print this help text
-v Print version
-verbose Verbose output
+ -force Try to generate code even if the input classes seem not
+ consistent with RMI specification.
-1.2 Generate v 1.2 stubs (default)*
diff --git a/tools/gnu/classpath/tools/rmi/RMID.java b/tools/gnu/classpath/tools/rmi/RMID.java
new file mode 100644
index 000000000..81d09671a
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/RMID.java
@@ -0,0 +1,189 @@
+/* RMID.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.rmi;
+
+import gnu.classpath.tools.HelpPrinter;
+import gnu.classpath.tools.rmi.rmid.ActivationSystemImpl;
+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 RMID
+{
+ /**
+ * 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";
+
+ /**
+ * The RMI activation daemon entry point.
+ */
+ public static void main(String[] args)
+ {
+ String HelpPath = "rmi/RMID.txt";
+ HelpPrinter.checkHelpKey(args, HelpPath);
+
+ // Parse parameters:
+ boolean stop = false;
+ String folder = ".";
+ boolean cold = false;
+ boolean trans = false;
+
+ for (int i = 0; i < args.length; i++)
+ {
+ String a = args[i];
+ if (a.equals("-verbose"))
+ ActivationSystemTransient.debug = true;
+ else if (a.equals("-stop"))
+ stop = true;
+ else if (a.equals("-restart"))
+ cold = true;
+ else if (a.equals("-transient"))
+ trans = true;
+ else if (i < args.length - 1)
+ {
+ // The additional key parameter is possible.
+ if (a.equals("-port"))
+ ACTIVATION_REGISTRY_PORT = Integer.parseInt(args[++i]);
+ else if (a.equals("-folder"))
+ folder = args[++i];
+ }
+ }
+
+ try
+ {
+ if (!stop)
+ {
+ // Start the system.
+ File dataFolder = new File(folder);
+ if (!dataFolder.exists())
+ dataFolder.mkdirs();
+ ActivationSystem system;
+
+ if (trans)
+ system = ActivationSystemTransient.getInstance();
+ else
+ system = ActivationSystemImpl.getInstance(dataFolder, 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();
+ }
+ }
+}
diff --git a/tools/gnu/classpath/tools/rmi/RMID.txt b/tools/gnu/classpath/tools/rmi/RMID.txt
new file mode 100644
index 000000000..a62613fd4
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/RMID.txt
@@ -0,0 +1,30 @@
+The persistent RMI activation daemon, support RMI object activation
+(package java.rmi.activation.*).
+
+Copyright 2006 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+Please report bugs at http://www.gnu.org/software/classpath/bugs.html
+
+Usage: rmid <options>
+
+ where <options> includes:
+ -port N Start the service on the given local port. If this key
+ is not specified, the service starts on the port 1098.
+ -verbose Log registration events to stdout.
+ -stop Stop the running activation service at the given port.
+
+ -transient Start transient activation service that does not write any
+ data to the disk. Such service looses the stored activation
+ descriptors, if restarted. If this key is not specified, the
+ persistent naming service is started.
+ -restart "Cold start:, clear the activation descriptor database, if any.
+ -folder Folder Store the persistent descriptor file in the given folder. If this
+ key is not specified, the file with persistent activation
+ information is stored into the current folder.
+
+All activation groups are activated on the same virtual machine, where the
+daemon is running. For security reasons, all the classes, required for
+activation, must be available in the classpath of that machine.
+ \ No newline at end of file
diff --git a/tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java
new file mode 100644
index 000000000..90bd3a6bd
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java
@@ -0,0 +1,139 @@
+/* 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.rmi.registry;
+
+import gnu.classpath.tools.rmi.Persistent;
+import gnu.classpath.tools.rmi.REGISTRY;
+
+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 (REGISTRY.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(REGISTRY.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 (REGISTRY.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 (REGISTRY.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/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Skel.java b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Skel.java
new file mode 100644
index 000000000..36b7d94a5
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/registry/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.rmi.registry;
+
+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/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Stub.java b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Stub.java
new file mode 100644
index 000000000..d8cac5bfc
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/registry/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.rmi.registry;
+
+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/tools/gnu/classpath/tools/rmi/registry/package.html b/tools/gnu/classpath/tools/rmi/registry/package.html
new file mode 100644
index 000000000..71df83b61
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/registry/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.rmi.registry package.
+ 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., 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.classpath.tools.rmi.registry</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
diff --git a/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java b/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java
index 9b7f9358b..8da486571 100644
--- a/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java
+++ b/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java
@@ -22,18 +22,7 @@
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.rmi.rmic;
@@ -43,7 +32,6 @@ import gnu.java.rmi.server.RMIHashes;
import java.lang.reflect.Method;
import java.util.Properties;
-import java.util.zip.Adler32;
/**
* Keeps information about the single method and generates the code fragments,
diff --git a/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java b/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java
index 498dff7b2..bc51aad38 100644
--- a/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java
+++ b/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java
@@ -22,18 +22,7 @@ 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.rmi.rmic;
diff --git a/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java b/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java
index 6451a7074..8ee4fa5f2 100644
--- a/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java
+++ b/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java
@@ -17,28 +17,11 @@ 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.rmi.rmic;
-import java.lang.reflect.Method;
public class WrapUnWrapper
{
diff --git a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav
index 1069884b9..9aaf8f5ad 100644
--- a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav
+++ b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav
@@ -19,7 +19,7 @@
catch (Exception e)
{
UnexpectedException uex = new UnexpectedException(exception_message);
- uex.initCause(e);
+ uex.detail = e;
throw uex;
}
}
diff --git a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav
index f67098a4f..860a93c84 100644
--- a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav
+++ b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav
@@ -18,7 +18,7 @@
catch (Exception e)
{
UnexpectedException uex = new UnexpectedException(exception_message);
- uex.initCause(e);
+ uex.detail = e;
throw uex;
}
}
diff --git a/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java b/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java
new file mode 100644
index 000000000..dda40b06c
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java
@@ -0,0 +1,244 @@
+/* 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.rmi.rmid;
+
+import gnu.classpath.tools.rmi.Persistent;
+import gnu.classpath.tools.rmi.PersistentBidiHashTable;
+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/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl_Stub.java b/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl_Stub.java
new file mode 100644
index 000000000..22fa10e4b
--- /dev/null
+++ b/tools/gnu/classpath/tools/rmi/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.rmi.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/tools/jarsigner.in b/tools/jarsigner.in
new file mode 100644
index 000000000..cea95a288
--- /dev/null
+++ b/tools/jarsigner.in
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+## Copyright (C) 2006 Free Software Foundation, Inc.
+##
+## This file is a 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 of the License, 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; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, 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.
+##
+##
+## A simple shell script to launch the GNU Classpath jarsigner tool.
+##
+
+prefix=@prefix@
+tools_dir=@datadir@/@PACKAGE@
+tools_cp=${tools_dir}/tools.zip
+
+# find the java executable...
+if [ -z "${JAVA}" ] ; then
+ if [ -n "${JAVA_HOME}" ] ; then
+ if [ -x "${JAVA_HOME}/jre/sh/java" ] ; then
+ JAVA="${JAVA_HOME}/jre/sh/java"
+ else
+ JAVA="${JAVA_HOME}/bin/java"
+ fi
+ else
+ JAVA=`which java 2> /dev/null `
+ if [ -z "${JAVA}" ] ; then
+ JAVA=java
+ fi
+ fi
+fi
+
+exec "${JAVA}" -Xbootclasspath/p:"${tools_cp}" gnu.classpath.tools.jarsigner.Main $@
diff --git a/tools/keytool.in b/tools/keytool.in
new file mode 100644
index 000000000..6c11dc407
--- /dev/null
+++ b/tools/keytool.in
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+## Copyright (C) 2006 Free Software Foundation, Inc.
+##
+## This file is a 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 of the License, 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; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, 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.
+##
+##
+## A simple shell script to launch the GNU Classpath keytool tool.
+##
+
+prefix=@prefix@
+tools_dir=@datadir@/@PACKAGE@
+tools_cp=${tools_dir}/tools.zip
+
+# find the java executable...
+if [ -z "${JAVA}" ] ; then
+ if [ -n "${JAVA_HOME}" ] ; then
+ if [ -x "${JAVA_HOME}/jre/sh/java" ] ; then
+ JAVA="${JAVA_HOME}/jre/sh/java"
+ else
+ JAVA="${JAVA_HOME}/bin/java"
+ fi
+ else
+ JAVA=`which java 2> /dev/null `
+ if [ -z "${JAVA}" ] ; then
+ JAVA=java
+ fi
+ fi
+fi
+
+exec "${JAVA}" -Xbootclasspath/p:"${tools_cp}" gnu.classpath.tools.keytool.Main $@