aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/sun/rmi/rmic/Main.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/sun/rmi/rmic/Main.java')
-rw-r--r--src/share/classes/sun/rmi/rmic/Main.java884
1 files changed, 884 insertions, 0 deletions
diff --git a/src/share/classes/sun/rmi/rmic/Main.java b/src/share/classes/sun/rmi/rmic/Main.java
new file mode 100644
index 000000000..bb9719aaf
--- /dev/null
+++ b/src/share/classes/sun/rmi/rmic/Main.java
@@ -0,0 +1,884 @@
+/*
+ * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * Licensed Materials - Property of IBM
+ * RMI-IIOP v1.0
+ * Copyright IBM Corp. 1998 1999 All Rights Reserved
+ *
+ */
+
+package sun.rmi.rmic;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+import java.util.MissingResourceException;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.ByteArrayOutputStream;
+
+import sun.tools.java.ClassFile;
+import sun.tools.java.ClassDefinition;
+import sun.tools.java.ClassDeclaration;
+import sun.tools.java.ClassNotFound;
+import sun.tools.java.Identifier;
+import sun.tools.java.ClassPath;
+
+import sun.tools.javac.SourceClass;
+import sun.tools.util.CommandLine;
+import java.lang.reflect.Constructor;
+import java.util.Properties;
+
+/**
+ * Main "rmic" program.
+ *
+ * WARNING: The contents of this source file are not part of any
+ * supported API. Code that depends on them does so at its own risk:
+ * they are subject to change or removal without notice.
+ */
+public class Main implements sun.rmi.rmic.Constants {
+ String sourcePathArg;
+ String sysClassPathArg;
+ String extDirsArg;
+ String classPathString;
+ File destDir;
+ int flags;
+ long tm;
+ Vector classes;
+ boolean nowrite;
+ boolean nocompile;
+ boolean keepGenerated;
+ boolean status;
+ String[] generatorArgs;
+ Vector generators;
+ Class environmentClass = BatchEnvironment.class;
+ boolean iiopGeneration = false;
+
+ /**
+ * Name of the program.
+ */
+ String program;
+
+ /**
+ * The stream where error message are printed.
+ */
+ OutputStream out;
+
+ /**
+ * Constructor.
+ */
+ public Main(OutputStream out, String program) {
+ this.out = out;
+ this.program = program;
+ }
+
+ /**
+ * Output a message.
+ */
+ public void output(String msg) {
+ PrintStream out =
+ this.out instanceof PrintStream ? (PrintStream)this.out
+ : new PrintStream(this.out, true);
+ out.println(msg);
+ }
+
+ /**
+ * Top level error message. This method is called when the
+ * environment could not be set up yet.
+ */
+ public void error(String msg) {
+ output(getText(msg));
+ }
+
+ public void error(String msg, String arg1) {
+ output(getText(msg, arg1));
+ }
+
+ public void error(String msg, String arg1, String arg2) {
+ output(getText(msg, arg1, arg2));
+ }
+
+ /**
+ * Usage
+ */
+ public void usage() {
+ error("rmic.usage", program);
+ }
+
+ /**
+ * Run the compiler
+ */
+ public synchronized boolean compile(String argv[]) {
+
+ /*
+ * Handle internal option to use the new (and incomplete) rmic
+ * implementation. This option is handled here, rather than
+ * in parseArgs, so that none of the arguments will be nulled
+ * before delegating to the new implementation.
+ */
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i].equals("-Xnew")) {
+ return (new sun.rmi.rmic.newrmic.Main(out,
+ program)).compile(argv);
+ }
+ }
+
+ if (!parseArgs(argv)) {
+ return false;
+ }
+
+ if (classes.size() == 0) {
+ usage();
+ return false;
+ }
+
+ return doCompile();
+ }
+
+ /**
+ * Get the destination directory.
+ */
+ public File getDestinationDir() {
+ return destDir;
+ }
+
+ /**
+ * Parse the arguments for compile.
+ */
+ public boolean parseArgs(String argv[]) {
+ sourcePathArg = null;
+ sysClassPathArg = null;
+ extDirsArg = null;
+
+ classPathString = null;
+ destDir = null;
+ flags = F_WARNINGS;
+ tm = System.currentTimeMillis();
+ classes = new Vector();
+ nowrite = false;
+ nocompile = false;
+ keepGenerated = false;
+ generatorArgs = getArray("generator.args",true);
+ if (generatorArgs == null) {
+ return false;
+ }
+ generators = new Vector();
+
+ // Pre-process command line for @file arguments
+ try {
+ argv = CommandLine.parse(argv);
+ } catch (FileNotFoundException e) {
+ error("rmic.cant.read", e.getMessage());
+ return false;
+ } catch (IOException e) {
+ e.printStackTrace(out instanceof PrintStream ?
+ (PrintStream) out :
+ new PrintStream(out, true));
+ return false;
+ }
+
+ // Parse arguments
+ for (int i = 0 ; i < argv.length ; i++) {
+ if (argv[i] != null) {
+ if (argv[i].equals("-g")) {
+ flags &= ~F_OPT;
+ flags |= F_DEBUG_LINES | F_DEBUG_VARS;
+ argv[i] = null;
+ } else if (argv[i].equals("-O")) {
+ flags &= ~F_DEBUG_LINES;
+ flags &= ~F_DEBUG_VARS;
+ flags |= F_OPT | F_DEPENDENCIES;
+ argv[i] = null;
+ } else if (argv[i].equals("-nowarn")) {
+ flags &= ~F_WARNINGS;
+ argv[i] = null;
+ } else if (argv[i].equals("-debug")) {
+ flags |= F_DUMP;
+ argv[i] = null;
+ } else if (argv[i].equals("-depend")) {
+ flags |= F_DEPENDENCIES;
+ argv[i] = null;
+ } else if (argv[i].equals("-verbose")) {
+ flags |= F_VERBOSE;
+ argv[i] = null;
+ } else if (argv[i].equals("-nowrite")) {
+ nowrite = true;
+ argv[i] = null;
+ } else if (argv[i].equals("-Xnocompile")) {
+ nocompile = true;
+ keepGenerated = true;
+ argv[i] = null;
+ } else if (argv[i].equals("-keep") ||
+ argv[i].equals("-keepgenerated")) {
+ keepGenerated = true;
+ argv[i] = null;
+ } else if (argv[i].equals("-show")) {
+ error("rmic.option.unsupported", "-show");
+ usage();
+ return false;
+ } else if (argv[i].equals("-classpath")) {
+ if ((i + 1) < argv.length) {
+ if (classPathString != null) {
+ error("rmic.option.already.seen", "-classpath");
+ usage();
+ return false;
+ }
+ argv[i] = null;
+ classPathString = argv[++i];
+ argv[i] = null;
+ } else {
+ error("rmic.option.requires.argument", "-classpath");
+ usage();
+ return false;
+ }
+ } else if (argv[i].equals("-sourcepath")) {
+ if ((i + 1) < argv.length) {
+ if (sourcePathArg != null) {
+ error("rmic.option.already.seen", "-sourcepath");
+ usage();
+ return false;
+ }
+ argv[i] = null;
+ sourcePathArg = argv[++i];
+ argv[i] = null;
+ } else {
+ error("rmic.option.requires.argument", "-sourcepath");
+ usage();
+ return false;
+ }
+ } else if (argv[i].equals("-bootclasspath")) {
+ if ((i + 1) < argv.length) {
+ if (sysClassPathArg != null) {
+ error("rmic.option.already.seen", "-bootclasspath");
+ usage();
+ return false;
+ }
+ argv[i] = null;
+ sysClassPathArg = argv[++i];
+ argv[i] = null;
+ } else {
+ error("rmic.option.requires.argument", "-bootclasspath");
+ usage();
+ return false;
+ }
+ } else if (argv[i].equals("-extdirs")) {
+ if ((i + 1) < argv.length) {
+ if (extDirsArg != null) {
+ error("rmic.option.already.seen", "-extdirs");
+ usage();
+ return false;
+ }
+ argv[i] = null;
+ extDirsArg = argv[++i];
+ argv[i] = null;
+ } else {
+ error("rmic.option.requires.argument", "-extdirs");
+ usage();
+ return false;
+ }
+ } else if (argv[i].equals("-d")) {
+ if ((i + 1) < argv.length) {
+ if (destDir != null) {
+ error("rmic.option.already.seen", "-d");
+ usage();
+ return false;
+ }
+ argv[i] = null;
+ destDir = new File(argv[++i]);
+ argv[i] = null;
+ if (!destDir.exists()) {
+ error("rmic.no.such.directory", destDir.getPath());
+ usage();
+ return false;
+ }
+ } else {
+ error("rmic.option.requires.argument", "-d");
+ usage();
+ return false;
+ }
+ } else {
+ if (!checkGeneratorArg(argv,i)) {
+ usage();
+ return false;
+ }
+ }
+ }
+ }
+
+
+ // Now that all generators have had a chance at the args,
+ // scan what's left for classes and illegal args...
+
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i] != null) {
+ if (argv[i].startsWith("-")) {
+ error("rmic.no.such.option", argv[i]);
+ usage();
+ return false;
+ } else {
+ classes.addElement(argv[i]);
+ }
+ }
+ }
+
+
+ // If the generators vector is empty, add the default generator...
+
+ if (generators.size() == 0) {
+ addGenerator("default");
+ }
+
+ return true;
+ }
+
+ /**
+ * If this argument is for a generator, instantiate it, call
+ * parseArgs(...) and add generator to generators vector.
+ * Returns false on error.
+ */
+ protected boolean checkGeneratorArg(String[] argv, int currentIndex) {
+ boolean result = true;
+ if (argv[currentIndex].startsWith("-")) {
+ String arg = argv[currentIndex].substring(1).toLowerCase(); // Remove '-'
+ for (int i = 0; i < generatorArgs.length; i++) {
+ if (arg.equalsIgnoreCase(generatorArgs[i])) {
+ // Got a match, add Generator and call parseArgs...
+ Generator gen = addGenerator(arg);
+ if (gen == null) {
+ return false;
+ }
+ result = gen.parseArgs(argv,this);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Instantiate and add a generator to the generators array.
+ */
+ protected Generator addGenerator(String arg) {
+
+ Generator gen;
+
+ // Create an instance of the generator and add it to
+ // the array...
+
+ String className = getString("generator.class." + arg);
+ if (className == null) {
+ error("rmic.missing.property",arg);
+ return null;
+ }
+
+ try {
+ gen = (Generator) Class.forName(className).newInstance();
+ } catch (Exception e) {
+ error("rmic.cannot.instantiate",className);
+ return null;
+ }
+
+ generators.addElement(gen);
+
+ // Get the environment required by this generator...
+
+ Class envClass = BatchEnvironment.class;
+ String env = getString("generator.env." + arg);
+ if (env != null) {
+ try {
+ envClass = Class.forName(env);
+
+ // Is the new class a subclass of the current one?
+
+ if (environmentClass.isAssignableFrom(envClass)) {
+
+ // Yes, so switch to the new one...
+
+ environmentClass = envClass;
+
+ } else {
+
+ // No. Is the current class a subclass of the
+ // new one?
+
+ if (!envClass.isAssignableFrom(environmentClass)) {
+
+ // No, so it's a conflict...
+
+ error("rmic.cannot.use.both",environmentClass.getName(),envClass.getName());
+ return null;
+ }
+ }
+ } catch (ClassNotFoundException e) {
+ error("rmic.class.not.found",env);
+ return null;
+ }
+ }
+
+ // If this is the iiop stub generator, cache
+ // that fact for the jrmp generator...
+
+ if (arg.equals("iiop")) {
+ iiopGeneration = true;
+ }
+ return gen;
+ }
+
+ /**
+ * Grab a resource string and parse it into an array of strings. Assumes
+ * comma separated list.
+ * @param name The resource name.
+ * @param mustExist If true, throws error if resource does not exist. If
+ * false and resource does not exist, returns zero element array.
+ */
+ protected String[] getArray(String name, boolean mustExist) {
+ String[] result = null;
+ String value = getString(name);
+ if (value == null) {
+ if (mustExist) {
+ error("rmic.resource.not.found",name);
+ return null;
+ } else {
+ return new String[0];
+ }
+ }
+
+ StringTokenizer parser = new StringTokenizer(value,", \t\n\r", false);
+ int count = parser.countTokens();
+ result = new String[count];
+ for (int i = 0; i < count; i++) {
+ result[i] = parser.nextToken();
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the correct type of BatchEnvironment
+ */
+ public BatchEnvironment getEnv() {
+
+ ClassPath classPath =
+ BatchEnvironment.createClassPath(classPathString,
+ sysClassPathArg,
+ extDirsArg);
+ BatchEnvironment result = null;
+ try {
+ Class[] ctorArgTypes = {OutputStream.class,ClassPath.class,Main.class};
+ Object[] ctorArgs = {out,classPath,this};
+ Constructor constructor = environmentClass.getConstructor(ctorArgTypes);
+ result = (BatchEnvironment) constructor.newInstance(ctorArgs);
+ result.reset();
+ }
+ catch (Exception e) {
+ error("rmic.cannot.instantiate",environmentClass.getName());
+ }
+ return result;
+ }
+
+
+ /**
+ * Do the compile with the switches and files already supplied
+ */
+ public boolean doCompile() {
+ // Create batch environment
+ BatchEnvironment env = getEnv();
+ env.flags |= flags;
+
+ // Set the classfile version numbers
+ // Compat and 1.1 stubs must retain the old version number.
+ env.majorVersion = 45;
+ env.minorVersion = 3;
+
+ // Preload the "out of memory" error string just in case we run
+ // out of memory during the compile.
+ String noMemoryErrorString = getText("rmic.no.memory");
+ String stackOverflowErrorString = getText("rmic.stack.overflow");
+
+ try {
+ /** Load the classes on the command line
+ * Replace the entries in classes with the ClassDefinition for the class
+ */
+ for (int i = classes.size()-1; i >= 0; i-- ) {
+ Identifier implClassName =
+ Identifier.lookup((String)classes.elementAt(i));
+
+ /*
+ * Fix bugid 4049354: support using '.' as an inner class
+ * qualifier on the command line (previously, only mangled
+ * inner class names were understood, like "pkg.Outer$Inner").
+ *
+ * The following method, also used by "javap", resolves the
+ * given unmangled inner class name to the appropriate
+ * internal identifier. For example, it translates
+ * "pkg.Outer.Inner" to "pkg.Outer. Inner".
+ */
+ implClassName = env.resolvePackageQualifiedName(implClassName);
+ /*
+ * But if we use such an internal inner class name identifier
+ * to load the class definition, the Java compiler will notice
+ * if the impl class is a "private" inner class and then deny
+ * skeletons (needed unless "-v1.2" is used) the ability to
+ * cast to it. To work around this problem, we mangle inner
+ * class name identifiers to their binary "outer" class name:
+ * "pkg.Outer. Inner" becomes "pkg.Outer$Inner".
+ */
+ implClassName = Names.mangleClass(implClassName);
+
+ ClassDeclaration decl = env.getClassDeclaration(implClassName);
+ try {
+ ClassDefinition def = decl.getClassDefinition(env);
+ for (int j = 0; j < generators.size(); j++) {
+ Generator gen = (Generator)generators.elementAt(j);
+ gen.generate(env, def, destDir);
+ }
+ } catch (ClassNotFound ex) {
+ env.error(0, "rmic.class.not.found", implClassName);
+ }
+
+ }
+
+ // compile all classes that need compilation
+ if (!nocompile) {
+ compileAllClasses(env);
+ }
+ } catch (OutOfMemoryError ee) {
+ // The compiler has run out of memory. Use the error string
+ // which we preloaded.
+ env.output(noMemoryErrorString);
+ return false;
+ } catch (StackOverflowError ee) {
+ env.output(stackOverflowErrorString);
+ return false;
+ } catch (Error ee) {
+ // We allow the compiler to take an exception silently if a program
+ // error has previously been detected. Presumably, this makes the
+ // compiler more robust in the face of bad error recovery.
+ if (env.nerrors == 0 || env.dump()) {
+ env.error(0, "fatal.error");
+ ee.printStackTrace(out instanceof PrintStream ?
+ (PrintStream) out :
+ new PrintStream(out, true));
+ }
+ } catch (Exception ee) {
+ if (env.nerrors == 0 || env.dump()) {
+ env.error(0, "fatal.exception");
+ ee.printStackTrace(out instanceof PrintStream ?
+ (PrintStream) out :
+ new PrintStream(out, true));
+ }
+ }
+
+ env.flushErrors();
+
+ boolean status = true;
+ if (env.nerrors > 0) {
+ String msg = "";
+ if (env.nerrors > 1) {
+ msg = getText("rmic.errors", env.nerrors);
+ } else {
+ msg = getText("rmic.1error");
+ }
+ if (env.nwarnings > 0) {
+ if (env.nwarnings > 1) {
+ msg += ", " + getText("rmic.warnings", env.nwarnings);
+ } else {
+ msg += ", " + getText("rmic.1warning");
+ }
+ }
+ output(msg);
+ status = false;
+ } else {
+ if (env.nwarnings > 0) {
+ if (env.nwarnings > 1) {
+ output(getText("rmic.warnings", env.nwarnings));
+ } else {
+ output(getText("rmic.1warning"));
+ }
+ }
+ }
+
+ // last step is to delete generated source files
+ if (!keepGenerated) {
+ env.deleteGeneratedFiles();
+ }
+
+ // We're done
+ if (env.verbose()) {
+ tm = System.currentTimeMillis() - tm;
+ output(getText("rmic.done_in", Long.toString(tm)));
+ }
+
+ // Shutdown the environment object and release our resources.
+ // Note that while this is unneccessary when rmic is invoked
+ // the command line, there are environments in which rmic
+ // from is invoked within a server process, so resource
+ // reclamation is important...
+
+ env.shutdown();
+
+ sourcePathArg = null;
+ sysClassPathArg = null;
+ extDirsArg = null;
+ classPathString = null;
+ destDir = null;
+ classes = null;
+ generatorArgs = null;
+ generators = null;
+ environmentClass = null;
+ program = null;
+ out = null;
+
+ return status;
+ }
+
+ /*
+ * Compile all classes that need to be compiled.
+ */
+ public void compileAllClasses (BatchEnvironment env)
+ throws ClassNotFound,
+ IOException,
+ InterruptedException {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(4096);
+ boolean done;
+
+ do {
+ done = true;
+ for (Enumeration e = env.getClasses() ; e.hasMoreElements() ; ) {
+ ClassDeclaration c = (ClassDeclaration)e.nextElement();
+ done = compileClass(c,buf,env);
+ }
+ } while (!done);
+ }
+
+ /*
+ * Compile a single class.
+ */
+ public boolean compileClass (ClassDeclaration c,
+ ByteArrayOutputStream buf,
+ BatchEnvironment env)
+ throws ClassNotFound,
+ IOException,
+ InterruptedException {
+ boolean done = true;
+ env.flushErrors();
+ SourceClass src;
+
+ switch (c.getStatus()) {
+ case CS_UNDEFINED:
+ {
+ if (!env.dependencies()) {
+ break;
+ }
+ // fall through
+ }
+
+ case CS_SOURCE:
+ {
+ done = false;
+ env.loadDefinition(c);
+ if (c.getStatus() != CS_PARSED) {
+ break;
+ }
+ // fall through
+ }
+
+ case CS_PARSED:
+ {
+ if (c.getClassDefinition().isInsideLocal()) {
+ break;
+ }
+ // If we get to here, then compilation is going
+ // to occur. If the -Xnocompile switch is set
+ // then fail. Note that this check is required
+ // here because this method is called from
+ // generators, not just from within this class...
+
+ if (nocompile) {
+ throw new IOException("Compilation required, but -Xnocompile option in effect");
+ }
+
+ done = false;
+
+ src = (SourceClass)c.getClassDefinition(env);
+ src.check(env);
+ c.setDefinition(src, CS_CHECKED);
+ // fall through
+ }
+
+ case CS_CHECKED:
+ {
+ src = (SourceClass)c.getClassDefinition(env);
+ // bail out if there were any errors
+ if (src.getError()) {
+ c.setDefinition(src, CS_COMPILED);
+ break;
+ }
+ done = false;
+ buf.reset();
+ src.compile(buf);
+ c.setDefinition(src, CS_COMPILED);
+ src.cleanup(env);
+
+ if (src.getError() || nowrite) {
+ break;
+ }
+
+ String pkgName = c.getName().getQualifier().toString().replace('.', File.separatorChar);
+ String className = c.getName().getFlatName().toString().replace('.', SIGC_INNERCLASS) + ".class";
+
+ File file;
+ if (destDir != null) {
+ if (pkgName.length() > 0) {
+ file = new File(destDir, pkgName);
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+ file = new File(file, className);
+ } else {
+ file = new File(destDir, className);
+ }
+ } else {
+ ClassFile classfile = (ClassFile)src.getSource();
+ if (classfile.isZipped()) {
+ env.error(0, "cant.write", classfile.getPath());
+ break;
+ }
+ file = new File(classfile.getPath());
+ file = new File(file.getParent(), className);
+ }
+
+ // Create the file
+ try {
+ FileOutputStream out = new FileOutputStream(file.getPath());
+ buf.writeTo(out);
+ out.close();
+ if (env.verbose()) {
+ output(getText("rmic.wrote", file.getPath()));
+ }
+ } catch (IOException ee) {
+ env.error(0, "cant.write", file.getPath());
+ }
+ }
+ }
+ return done;
+ }
+
+ /**
+ * Main program
+ */
+ public static void main(String argv[]) {
+ Main compiler = new Main(System.out, "rmic");
+ System.exit(compiler.compile(argv) ? 0 : 1);
+ }
+
+ /**
+ * Return the string value of a named resource in the rmic.properties
+ * resource bundle. If the resource is not found, null is returned.
+ */
+ public static String getString(String key) {
+ if (!resourcesInitialized) {
+ initResources();
+ }
+
+ // To enable extensions, search the 'resourcesExt'
+ // bundle first, followed by the 'resources' bundle...
+
+ if (resourcesExt != null) {
+ try {
+ return resourcesExt.getString(key);
+ } catch (MissingResourceException e) {}
+ }
+
+ try {
+ return resources.getString(key);
+ } catch (MissingResourceException ignore) {
+ }
+ return null;
+ }
+
+ private static boolean resourcesInitialized = false;
+ private static ResourceBundle resources;
+ private static ResourceBundle resourcesExt = null;
+
+ private static void initResources() {
+ try {
+ resources =
+ ResourceBundle.getBundle("sun.rmi.rmic.resources.rmic");
+ resourcesInitialized = true;
+ try {
+ resourcesExt =
+ ResourceBundle.getBundle("sun.rmi.rmic.resources.rmicext");
+ } catch (MissingResourceException e) {}
+ } catch (MissingResourceException e) {
+ throw new Error("fatal: missing resource bundle: " +
+ e.getClassName());
+ }
+ }
+
+ public static String getText(String key) {
+ String message = getString(key);
+ if (message == null) {
+ message = "no text found: \"" + key + "\"";
+ }
+ return message;
+ }
+
+ public static String getText(String key, int num) {
+ return getText(key, Integer.toString(num), null, null);
+ }
+
+ public static String getText(String key, String arg0) {
+ return getText(key, arg0, null, null);
+ }
+
+ public static String getText(String key, String arg0, String arg1) {
+ return getText(key, arg0, arg1, null);
+ }
+
+ public static String getText(String key,
+ String arg0, String arg1, String arg2)
+ {
+ String format = getString(key);
+ if (format == null) {
+ format = "no text found: key = \"" + key + "\", " +
+ "arguments = \"{0}\", \"{1}\", \"{2}\"";
+ }
+
+ String[] args = new String[3];
+ args[0] = (arg0 != null ? arg0.toString() : "null");
+ args[1] = (arg1 != null ? arg1.toString() : "null");
+ args[2] = (arg2 != null ? arg2.toString() : "null");
+
+ return java.text.MessageFormat.format(format, args);
+ }
+}