This is an automated email from the ASF dual-hosted git repository. remm pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomcat-jakartaee-migration.git
The following commit(s) were added to refs/heads/master by this push: new 873d7af Add i18n and some validation 873d7af is described below commit 873d7afeba2ce603db0a98d6f6b3a3ce52ace265 Author: remm <r...@apache.org> AuthorDate: Thu Jan 16 12:53:36 2020 +0100 Add i18n and some validation --- .../org/apache/tomcat/jakartaee/Migration.java | 46 ++-- .../org/apache/tomcat/jakartaee/StringManager.java | 292 +++++++++++++++++++++ .../tomcat/jakartaee/LocalStrings.properties | 23 ++ 3 files changed, 346 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/apache/tomcat/jakartaee/Migration.java b/src/main/java/org/apache/tomcat/jakartaee/Migration.java index c81dfd7..bc7744b 100644 --- a/src/main/java/org/apache/tomcat/jakartaee/Migration.java +++ b/src/main/java/org/apache/tomcat/jakartaee/Migration.java @@ -30,9 +30,14 @@ import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; +import java.util.logging.Level; +import java.util.logging.Logger; public class Migration { + private static final Logger logger = Logger.getLogger(Migration.class.getCanonicalName()); + private static final StringManager sm = StringManager.getManager(Migration.class); + private File source; private File destination; private final List<Converter> converters; @@ -51,29 +56,38 @@ public class Migration { public void setSource(File source) { if (!source.canRead()) { - // TODO i18n - throw new IllegalArgumentException(); + throw new IllegalArgumentException(sm.getString("migration.cannotReadSource", + source.getAbsolutePath())); } this.source = source; } public void setDestination(File destination) { - // TODO validate this.destination = destination; } public boolean execute() throws IOException { - // TODO validate arguments - + logger.log(Level.INFO, sm.getString("migration.execute", source.getAbsolutePath(), + destination.getAbsolutePath())); if (source.isDirectory()) { - migrateDirectory(source, destination); + if (destination.mkdirs()) { + migrateDirectory(source, destination); + } else { + logger.log(Level.SEVERE, sm.getString("migration.mkdirError", destination.getAbsolutePath())); + } } else { // Single file - migrateFile(source, destination); + File parentDestination = destination.getParentFile(); + if (parentDestination.exists() || parentDestination.mkdirs()) { + migrateFile(source, destination); + } else { + logger.log(Level.SEVERE, sm.getString("migration.mkdirError", parentDestination.getAbsolutePath())); + } } - return false; + logger.log(Level.INFO, sm.getString("migration.done")); + return true; } @@ -83,8 +97,11 @@ public class Migration { File srcFile = new File(src, file); File destFile = new File(dest, file); if (srcFile.isDirectory()) { - destFile.mkdirs(); - migrateDirectory(srcFile, destFile); + if (destFile.mkdir()) { + migrateDirectory(srcFile, destFile); + } else { + logger.log(Level.SEVERE, sm.getString("migration.mkdirError", destFile.getAbsolutePath())); + } } else { migrateFile(srcFile, destFile); } @@ -113,7 +130,7 @@ public class Migration { JarEntry jarEntry; while ((jarEntry = jarIs.getNextJarEntry()) != null) { String sourceName = jarEntry.getName(); - System.out.println("Migrating JarEntry [" + sourceName + "]"); + logger.log(Level.FINE, sm.getString("migration.entry", sourceName)); String destName = Util.convert(sourceName); JarEntry destEntry = new JarEntry(destName); jarOs.putNextEntry(destEntry); @@ -124,7 +141,7 @@ public class Migration { private void migrateStream(String name, InputStream src, OutputStream dest) throws IOException { - System.out.println("Migrating stream [" + name + "]"); + logger.log(Level.FINE, sm.getString("migration.stream", name)); if (isArchive(name)) { migrateArchive(src, dest); } else { @@ -166,8 +183,7 @@ public class Migration { try { result = migration.execute(); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + logger.log(Level.SEVERE, sm.getString("migration.error"), e); } // Signal caller that migration failed @@ -178,7 +194,7 @@ public class Migration { private static void usage() { - System.out.println("Usage: Migration <source> <destination>"); + System.out.println(sm.getString("migration.usage")); } diff --git a/src/main/java/org/apache/tomcat/jakartaee/StringManager.java b/src/main/java/org/apache/tomcat/jakartaee/StringManager.java new file mode 100644 index 0000000..7df8faf --- /dev/null +++ b/src/main/java/org/apache/tomcat/jakartaee/StringManager.java @@ -0,0 +1,292 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.jakartaee; + +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * An internationalization / localization helper class which reduces + * the bother of handling ResourceBundles and takes care of the + * common cases of message formatting which otherwise require the + * creation of Object arrays and such. + * + * <p>The StringManager operates on a package basis. One StringManager + * per package can be created and accessed via the getManager method + * call. + * + * <p>The StringManager will look for a ResourceBundle named by + * the package name given plus the suffix of "LocalStrings". In + * practice, this means that the localized information will be contained + * in a LocalStrings.properties file located in the package + * directory of the class path. + * + * <p>Please see the documentation for java.util.ResourceBundle for + * more information. + * + * @author James Duncan Davidson [dun...@eng.sun.com] + * @author James Todd [go...@eng.sun.com] + * @author Mel Martinez [mmarti...@g1440.com] + * @see java.util.ResourceBundle + */ +public class StringManager { + + private static int LOCALE_CACHE_SIZE = 10; + + /** + * The ResourceBundle for this StringManager. + */ + private final ResourceBundle bundle; + private final Locale locale; + + + /** + * Creates a new StringManager for a given package. This is a + * private method and all access to it is arbitrated by the + * static getManager method call so that only one StringManager + * per package will be created. + * + * @param packageName Name of package to create StringManager for. + */ + private StringManager(String packageName, Locale locale) { + String bundleName = packageName + ".LocalStrings"; + ResourceBundle bnd = null; + try { + // The ROOT Locale uses English. If English is requested, force the + // use of the ROOT Locale else incorrect results may be obtained if + // the system default locale is not English and translations are + // available for the system default locale. + if (locale.getLanguage().equals(Locale.ENGLISH.getLanguage())) { + locale = Locale.ROOT; + } + bnd = ResourceBundle.getBundle(bundleName, locale); + } catch (MissingResourceException ex) { + // Try from the current loader (that's the case for trusted apps) + // Should only be required if using a TC5 style classloader structure + // where common != shared != server + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl != null) { + try { + bnd = ResourceBundle.getBundle(bundleName, locale, cl); + } catch (MissingResourceException ex2) { + // Ignore + } + } + } + bundle = bnd; + // Get the actual locale, which may be different from the requested one + if (bundle != null) { + Locale bundleLocale = bundle.getLocale(); + if (bundleLocale.equals(Locale.ROOT)) { + this.locale = Locale.ENGLISH; + } else { + this.locale = bundleLocale; + } + } else { + this.locale = null; + } + } + + + /** + * Get a string from the underlying resource bundle or return null if the + * String is not found. + * + * @param key to desired resource String + * + * @return resource String matching <i>key</i> from underlying bundle or + * null if not found. + * + * @throws IllegalArgumentException if <i>key</i> is null + */ + public String getString(String key) { + if (key == null){ + String msg = "key may not have a null value"; + throw new IllegalArgumentException(msg); + } + + String str = null; + + try { + // Avoid NPE if bundle is null and treat it like an MRE + if (bundle != null) { + str = bundle.getString(key); + } + } catch (MissingResourceException mre) { + //bad: shouldn't mask an exception the following way: + // str = "[cannot find message associated with key '" + key + + // "' due to " + mre + "]"; + // because it hides the fact that the String was missing + // from the calling code. + //good: could just throw the exception (or wrap it in another) + // but that would probably cause much havoc on existing + // code. + //better: consistent with container pattern to + // simply return null. Calling code can then do + // a null check. + str = null; + } + + return str; + } + + + /** + * Get a string from the underlying resource bundle and format + * it with the given set of arguments. + * + * @param key The key for the required message + * @param args The values to insert into the message + * + * @return The request string formatted with the provided arguments or the + * key if the key was not found. + */ + public String getString(final String key, final Object... args) { + String value = getString(key); + if (value == null) { + value = key; + } + + MessageFormat mf = new MessageFormat(value); + mf.setLocale(locale); + return mf.format(args, new StringBuffer(), null).toString(); + } + + + /** + * Identify the Locale this StringManager is associated with. + * + * @return The Locale associated with the StringManager + */ + public Locale getLocale() { + return locale; + } + + + // -------------------------------------------------------------- + // STATIC SUPPORT METHODS + // -------------------------------------------------------------- + + private static final Map<String, Map<Locale,StringManager>> managers = + new Hashtable<>(); + + + /** + * Get the StringManager for a given class. The StringManager will be + * returned for the package in which the class is located. If a manager for + * that package already exists, it will be reused, else a new + * StringManager will be created and returned. + * + * @param clazz The class for which to retrieve the StringManager + * + * @return The instance associated with the package of the provide class + */ + public static final StringManager getManager(Class<?> clazz) { + return getManager(clazz.getPackage().getName()); + } + + + /** + * Get the StringManager for a particular package. If a manager for + * a package already exists, it will be reused, else a new + * StringManager will be created and returned. + * + * @param packageName The package name + * + * @return The instance associated with the given package and the default + * Locale + */ + public static final StringManager getManager(String packageName) { + return getManager(packageName, Locale.getDefault()); + } + + + /** + * Get the StringManager for a particular package and Locale. If a manager + * for a package/Locale combination already exists, it will be reused, else + * a new StringManager will be created and returned. + * + * @param packageName The package name + * @param locale The Locale + * + * @return The instance associated with the given package and Locale + */ + public static final synchronized StringManager getManager( + String packageName, Locale locale) { + + Map<Locale,StringManager> map = managers.get(packageName); + if (map == null) { + /* + * Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. + * Expansion occurs when size() exceeds capacity. Therefore keep + * size at or below capacity. + * removeEldestEntry() executes after insertion therefore the test + * for removal needs to use one less than the maximum desired size + * + */ + map = new LinkedHashMap<Locale,StringManager>(LOCALE_CACHE_SIZE, 1, true) { + private static final long serialVersionUID = 1L; + @Override + protected boolean removeEldestEntry( + Map.Entry<Locale,StringManager> eldest) { + if (size() > (LOCALE_CACHE_SIZE - 1)) { + return true; + } + return false; + } + }; + managers.put(packageName, map); + } + + StringManager mgr = map.get(locale); + if (mgr == null) { + mgr = new StringManager(packageName, locale); + map.put(locale, mgr); + } + return mgr; + } + + + /** + * Retrieve the StringManager for a list of Locales. The first StringManager + * found will be returned. + * + * @param packageName The package for which the StringManager was + * requested + * @param requestedLocales The list of Locales + * + * @return the found StringManager or the default StringManager + */ + public static StringManager getManager(String packageName, + Enumeration<Locale> requestedLocales) { + while (requestedLocales.hasMoreElements()) { + Locale locale = requestedLocales.nextElement(); + StringManager result = getManager(packageName, locale); + if (result.getLocale().equals(locale)) { + return result; + } + } + // Return the default + return getManager(packageName); + } +} diff --git a/src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties b/src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties new file mode 100644 index 0000000..b41be87 --- /dev/null +++ b/src/main/resources/org/apache/tomcat/jakartaee/LocalStrings.properties @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +migration.cannotReadSource=Cannot read source location [{0}] +migration.done=Migration done +migration.entry=Migrating Jar entry [{0}] +migration.error=Error performing migration +migration.execute=Performing migration from source [{0}] to destination [{1}] +migration.mkdirError=Error creating destination directory [{0}] +migration.stream=Migrating stream [{0}] +migration.usage=Usage: Migration <source> <destination> \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org