Java tutorial
/******************************************************************************* * Copyright 2011 Danny Kunz * * Licensed 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.omnaest.i18nbinder.internal; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.omnaest.i18nbinder.grouping.FileGroup; import org.omnaest.i18nbinder.grouping.FileGroupToPropertiesAdapter; import org.omnaest.i18nbinder.grouping.FileGrouper; import org.omnaest.utils.structure.collection.list.ListUtils; import org.omnaest.utils.structure.element.converter.ElementConverterElementToMapEntry; import org.omnaest.utils.structure.element.filter.ElementFilterNotBlank; import org.omnaest.utils.structure.hierarchy.TokenMonoHierarchy; import org.omnaest.utils.structure.hierarchy.TokenMonoHierarchy.TokenElementPath; import org.omnaest.utils.structure.map.SimpleEntry; /** * Helper to create a i18n facade Java source code file based on property files * * @author Omnaest */ public class FacadeCreatorHelper { /* ********************************************** Constants ********************************************** */ public static final String DEFAULT_JAVA_FACADE_FILENAME_I18N_FACADE = "I18nFacade"; public static final String LINE_SEPARATOR = System.getProperty("line.separator"); /* ********************************************** Methods ********************************************** */ /** * @param propertyFileSet * @param localeFilter * @param fileNameLocaleGroupPattern * @param groupingPatternGroupingGroupIndexList * @param i18nFacadeName * @param externalizeTypes * @param propertyfileEncoding * @return */ public static Map<String, String> createI18nInterfaceFacadeFromPropertyFiles(Set<File> propertyFileSet, LocaleFilter localeFilter, String fileNameLocaleGroupPattern, List<Integer> groupingPatternGroupingGroupIndexList, String baseNameInTargetPlattform, String baseFolderIgnoredPath, String packageName, String i18nFacadeName, boolean externalizeTypes, String propertyfileEncoding) { // final Map<String, String> retmap = new LinkedHashMap<String, String>(); // if (propertyFileSet != null) { // Map<String, FileGroup> fileGroupIdentifierToFileGroupMap; { FileGrouper fileGrouper = new FileGrouper(); try { if (fileNameLocaleGroupPattern != null) { fileGrouper.setGroupingPatternString(fileNameLocaleGroupPattern); } if (groupingPatternGroupingGroupIndexList != null) { fileGrouper.setGroupingPatternGroupingGroupIndexList(groupingPatternGroupingGroupIndexList); } } catch (Exception e) { ModifierHelper.logger.info(e.getMessage()); } fileGrouper.setGroupingPatternReplacementToken(""); fileGrouper.addAllFiles(propertyFileSet); fileGroupIdentifierToFileGroupMap = fileGrouper.determineFileGroupIdentifierToFileGroupMap(); } // List<FileGroupToPropertiesAdapter> fileGroupToPropertiesAdapterList = new ArrayList<FileGroupToPropertiesAdapter>(); { // for (String fileGroupIdentifier : fileGroupIdentifierToFileGroupMap.keySet()) { // FileGroup fileGroup = fileGroupIdentifierToFileGroupMap.get(fileGroupIdentifier); // FileGroupToPropertiesAdapter fileGroupToPropertiesAdapter = new FileGroupToPropertiesAdapter( fileGroup); fileGroupToPropertiesAdapter.setFileEncoding(propertyfileEncoding); // fileGroupToPropertiesAdapterList.add(fileGroupToPropertiesAdapter); } // Collections.sort(fileGroupToPropertiesAdapterList, new Comparator<FileGroupToPropertiesAdapter>() { @Override public int compare(FileGroupToPropertiesAdapter fileGroupToPropertiesAdapter1, FileGroupToPropertiesAdapter fileGroupToPropertiesAdapter2) { // String fileGroupIdentifier1 = fileGroupToPropertiesAdapter1.getFileGroup() .getFileGroupIdentifier(); String fileGroupIdentifier2 = fileGroupToPropertiesAdapter2.getFileGroup() .getFileGroupIdentifier(); // return fileGroupIdentifier1.compareTo(fileGroupIdentifier2); } }); } //determine all locales but fix the order List<String> localeList = new ArrayList<String>(); { // Set<String> localeSet = new HashSet<String>(); for (FileGroupToPropertiesAdapter fileGroupToPropertiesAdapter : fileGroupToPropertiesAdapterList) { localeSet.addAll(fileGroupToPropertiesAdapter.determineGroupTokenList()); } localeList.addAll(localeSet); // for (String locale : localeSet) { if (!localeFilter.isLocaleAccepted(locale)) { localeList.remove(locale); } } // Collections.sort(localeList); } //facade source code { // TokenMonoHierarchy<String, PropertyKeyAndValues> TokenMonoHierarchy = new TokenMonoHierarchy<String, PropertyKeyAndValues>(); // for (FileGroupToPropertiesAdapter fileGroupToPropertiesAdapter : fileGroupToPropertiesAdapterList) { // String fileGroupIdentifier = fileGroupToPropertiesAdapter.getFileGroup() .getFileGroupIdentifier(); // List<String> tokenPathElementList = new ArrayList<String>(); { // final String pathDelimiter = "[\\\\/]"; // if (StringUtils.isNotBlank(baseNameInTargetPlattform)) { // String[] baseNameTokens = baseNameInTargetPlattform.split(pathDelimiter); // tokenPathElementList.addAll(Arrays.asList(baseNameTokens)); } // String[] fileGroupIdentifierTokens = fileGroupIdentifier .replaceFirst(Pattern.quote(baseFolderIgnoredPath), "").split(pathDelimiter); if (fileGroupIdentifierTokens.length > 0) { // String lastToken = fileGroupIdentifierTokens[fileGroupIdentifierTokens.length - 1]; lastToken = lastToken.replaceAll("\\.properties$", "").replaceAll("_", ""); fileGroupIdentifierTokens[fileGroupIdentifierTokens.length - 1] = lastToken; // tokenPathElementList.addAll(Arrays.asList(fileGroupIdentifierTokens)); } // tokenPathElementList = ListUtils.filter(tokenPathElementList, new ElementFilterNotBlank()); } // ModifierHelper.logger.info("Processing: " + fileGroupIdentifier); // List<String> propertyKeyList = new ArrayList<String>( fileGroupToPropertiesAdapter.determinePropertyKeySet()); Collections.sort(propertyKeyList); for (String propertyKey : propertyKeyList) { if (propertyKey != null) { // PropertyKeyAndValues propertyKeyAndValues = new PropertyKeyAndValues(); { // propertyKeyAndValues.propertyKey = propertyKey; // for (String locale : localeList) { // String value = fileGroupToPropertiesAdapter.resolvePropertyValue(propertyKey, locale); value = StringUtils.defaultString(value); if (StringUtils.isNotBlank(value)) { propertyKeyAndValues.valueList.add(locale + "=" + value); } } } // TokenElementPath<String> tokenElementPath = new TokenElementPath<String>( tokenPathElementList); TokenMonoHierarchy.addTokenElementPathWithValues(tokenElementPath, propertyKeyAndValues); } } } // final Map<String, StringBuilder> externalizedClassToContentMap = externalizeTypes ? new LinkedHashMap<String, StringBuilder>() : null; retmap.put(packageName + "." + i18nFacadeName, buildFacadeSource(TokenMonoHierarchy, packageName, i18nFacadeName, externalizedClassToContentMap)); if (externalizeTypes) { for (String subClassName : externalizedClassToContentMap.keySet()) { // final StringBuilder stringBuilder = externalizedClassToContentMap.get(subClassName); retmap.put(subClassName, stringBuilder.toString()); } } } } // return retmap; } protected static class PropertyKeyAndValues { public String propertyKey = null; public List<String> valueList = new ArrayList<String>(); } private static String buildFacadeSource(TokenMonoHierarchy<String, PropertyKeyAndValues> TokenMonoHierarchy, String packageName, String i18nFacadeName, Map<String, StringBuilder> externalizedClassToContentMap) { // StringBuilder retval = new StringBuilder(); // TokenMonoHierarchy<String, PropertyKeyAndValues>.Navigator navigator = TokenMonoHierarchy.getNavigator(); // final String className = i18nFacadeName; final boolean isSubClass = false; final String rootPackageName = packageName; buildFacadeSource(retval, className, isSubClass, navigator, externalizedClassToContentMap, i18nFacadeName, packageName, rootPackageName); return retval.toString().replaceAll("\n", LINE_SEPARATOR); } private static void buildFacadeSource(StringBuilder stringBuilder, String className, boolean isSubClass, TokenMonoHierarchy<String, PropertyKeyAndValues>.Navigator navigator, Map<String, StringBuilder> externalizedClassToContentMap, String i18nFacadeName, String packageName, String rootPackageName) { // final Map<String, String> subClassNameToTokenElementMap = new LinkedHashMap<String, String>(); final Map<String, List<String>> propertyNameToExampleValueListMap = new LinkedHashMap<String, List<String>>(); final Map<String, String> propertyNameToPropertyKeyMap = new HashMap<String, String>(); final String baseName = StringUtils.join(navigator.determineTokenPathElementList(), "."); final boolean externalizeTypes = externalizedClassToContentMap != null; final boolean staticModifier = !externalizeTypes && isSubClass; // { // List<String> tokenElementOfChildrenList = navigator.getTokenElementOfChildrenList(); subClassNameToTokenElementMap.putAll(ListUtils.toMap(tokenElementOfChildrenList, new CamelCaseTokenElementToMapEntryConverter(className))); } final boolean hasAtLeastOneSubclass = !subClassNameToTokenElementMap.isEmpty(); { // if (navigator.hasValues()) { // List<PropertyKeyAndValues> propertyKeyAndValuesList = navigator.getValues(); for (PropertyKeyAndValues propertyKeyAndValues : propertyKeyAndValuesList) { // String propertyKey = propertyKeyAndValues.propertyKey; // String propertyName = ""; { // { // String[] tokens = propertyKey.split("[^a-zA-Z0-9]"); for (String token : tokens) { propertyName += StringUtils.capitalize(token); } } } // { // final String key = propertyName; final List<String> valueList = new ArrayList<String>(propertyKeyAndValues.valueList); { // final String defaultLocaleString = String.valueOf(Locale.getDefault()); final String defaultLocaleLanguageString = String .valueOf(Locale.getDefault().getLanguage()); Collections.sort(valueList, new Comparator<String>() { @Override public int compare(String o1, String o2) { // int retval = 0; // final String firstElement1 = org.omnaest.utils.structure.collection.list.ListUtils .firstElement(org.omnaest.utils.structure.collection.list.ListUtils .valueOf(StringUtils.split(o1, "="))); final String firstElement2 = org.omnaest.utils.structure.collection.list.ListUtils .firstElement(org.omnaest.utils.structure.collection.list.ListUtils .valueOf(StringUtils.split(o2, "="))); // if (StringUtils.startsWith(firstElement1, defaultLocaleString)) { retval--; } if (StringUtils.startsWith(firstElement2, defaultLocaleString)) { retval++; } if (StringUtils.contains(firstElement1, defaultLocaleString)) { retval--; } if (StringUtils.contains(firstElement2, defaultLocaleString)) { retval++; } if (StringUtils.contains(firstElement1, defaultLocaleLanguageString)) { retval--; } if (StringUtils.contains(firstElement2, defaultLocaleLanguageString)) { retval++; } // return retval; } }); } propertyNameToExampleValueListMap.put(key, valueList); } // { // propertyNameToPropertyKeyMap.put(propertyName, propertyKey); } } } } // boolean hasBaseName = StringUtils.isNotBlank(baseName); boolean hasProperties = !propertyNameToExampleValueListMap.keySet().isEmpty(); SortedSet<String> importSet = new TreeSet<String>(); int importOffset = 0; //imports if (!isSubClass || externalizeTypes) { // stringBuilder.append(StringUtils.isNotBlank(packageName) ? "package " + packageName + ";\n\n" : ""); importOffset = stringBuilder.length(); //stringBuilder.append( "import java.util.MissingResourceException;\n" ); importSet.add("java.util.Locale"); importSet.add("java.util.MissingResourceException"); importSet.add("javax.annotation.Generated"); // if (!isSubClass) { importSet.add("java.util.LinkedHashMap"); importSet.add("java.util.ResourceBundle"); } // if (externalizeTypes) { // if (hasProperties) { importSet.add(rootPackageName + "." + i18nFacadeName); importSet.add(rootPackageName + "." + i18nFacadeName + ".Translator"); } // if (hasAtLeastOneSubclass) { for (String subClassName : subClassNameToTokenElementMap.keySet()) { importSet.add(packageName + "." + StringUtils.lowerCase(className) + "." + subClassName); } } } } //documentation stringBuilder.append("/**\n"); stringBuilder.append(" * This is an automatically with i18nBinder generated facade class.<br><br>\n"); stringBuilder.append(" * To modify please adapt the underlying property files.<br><br>\n"); stringBuilder.append(" * If the facade class is instantiated with a given {@link Locale} using {@link #" + className + "(Locale)} all non static methods will use this predefined {@link Locale} when invoked.<br><br>\n"); stringBuilder.append( " * The facade methods will silently ignore all {@link MissingResourceException}s by default. To alter this behavior see {@link #" + className + "(Locale, boolean)}<br><br>\n"); stringBuilder.append(hasBaseName ? " * Resource base: <b>" + baseName + "</b>\n" : ""); // if (hasProperties) { printJavaDocPropertiesExamplesForSubclassAndInstance(stringBuilder, propertyNameToExampleValueListMap, propertyNameToPropertyKeyMap); } for (String subClassName : subClassNameToTokenElementMap.keySet()) { stringBuilder.append(" * @see " + subClassName + "\n"); } if (hasProperties) { stringBuilder.append(" * @see #translator()\n"); stringBuilder.append(" * @see #translator(Locale)\n"); } stringBuilder.append(" */ \n"); stringBuilder.append("@Generated(value = \"http://code.google.com/p/i18n-binder/\", date = \"" + DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(Calendar.getInstance()) + "\")\n"); //class stringBuilder.append("public " + (staticModifier ? "static " : "") + "class " + className + " {\n"); { //vars { // if (!propertyNameToExampleValueListMap.isEmpty()) { // stringBuilder.append(" public final static String baseName = \"" + baseName + "\";\n"); stringBuilder.append(" private final Locale locale;\n"); stringBuilder.append(" private final boolean silentlyIgnoreMissingResourceException;\n"); } // for (String subClassName : subClassNameToTokenElementMap.keySet()) { // stringBuilder.append(" /** @see " + subClassName + " */\n"); stringBuilder.append(" public final " + subClassName + " " + subClassName + ";\n"); } if (!isSubClass) { stringBuilder.append(" /** Static access helper for the underlying resource */\n"); stringBuilder.append(" public static class Resource\n"); stringBuilder.append(" {\n"); stringBuilder.append( " /** Internally used {@link ResourceBasedTranslator}. Changing this implementation affects the behavior of the whole facade */\n"); stringBuilder.append( " public static ResourceBasedTranslator resourceBasedTranslator = new ResourceBasedTranslator()\n"); stringBuilder.append(" {\n"); stringBuilder.append(" @Override\n"); stringBuilder.append( " public String translate( String baseName, String key, Locale locale )\n"); stringBuilder.append(" {\n"); stringBuilder.append( " ResourceBundle resourceBundle = ResourceBundle.getBundle( baseName,locale );\n"); stringBuilder.append(" return resourceBundle.getString( key );\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" @Override\n"); stringBuilder .append(" public String[] resolveAllKeys( String baseName, Locale locale )\n"); stringBuilder.append(" {\n"); stringBuilder.append( " ResourceBundle resourceBundle = ResourceBundle.getBundle( baseName,locale );\n"); stringBuilder.append(" return resourceBundle.keySet().toArray( new String[0] );\n"); stringBuilder.append(" }\n"); stringBuilder.append(" };\n\n"); stringBuilder.append(" }\n"); stringBuilder.append( " /** Defines which {@link ResourceBasedTranslator} the facade should use. This affects all available instances. */\n"); stringBuilder.append( " public static void use( ResourceBasedTranslator resourceBasedTranslator )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" " + i18nFacadeName + ".Resource.resourceBasedTranslator = resourceBasedTranslator;\n"); stringBuilder.append(" }\n\n"); } } //helper classes { if (!isSubClass) { importSet.add("java.util.Map"); appendResourceBasedTranslatorInterface(stringBuilder); appendTranslatorHelper(stringBuilder, i18nFacadeName); } } //constructor { // stringBuilder.append("\n"); stringBuilder.append(" /**\n"); stringBuilder.append(" * This {@link " + className + "} constructor will create a new instance which silently ignores any {@link MissingResourceException} \n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public " + className + "( Locale locale )\n"); stringBuilder.append(" {\n"); { // stringBuilder.append(" this(locale,true);\n"); } stringBuilder.append(" }\n"); stringBuilder.append(" \n"); // stringBuilder.append("\n"); stringBuilder.append(" /**\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" * @param silentlyIgnoreMissingResourceException\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public " + className + "( Locale locale, boolean silentlyIgnoreMissingResourceException )\n"); stringBuilder.append(" {\n"); { // stringBuilder.append(" super();\n"); if (!propertyNameToExampleValueListMap.isEmpty()) { stringBuilder.append(" this.locale = locale;\n"); stringBuilder.append( " this.silentlyIgnoreMissingResourceException = silentlyIgnoreMissingResourceException;\n"); } // for (String subClassName : subClassNameToTokenElementMap.keySet()) { stringBuilder.append(" this." + subClassName + " = new " + subClassName + "( locale, silentlyIgnoreMissingResourceException );\n"); } } stringBuilder.append(" }\n"); stringBuilder.append(" \n"); } //static subclasses { // for (String subClassName : subClassNameToTokenElementMap.keySet()) { // final boolean subClassIsSubClass = true; final String subClassPackageName = !externalizeTypes ? packageName : packageName + "." + StringUtils.lowerCase(className); final StringBuilder subClassStringBuilder; { // if (externalizeTypes) { subClassStringBuilder = new StringBuilder(); externalizedClassToContentMap.put(subClassPackageName + "." + subClassName, subClassStringBuilder); } else { subClassStringBuilder = stringBuilder; } } buildFacadeSource(subClassStringBuilder, subClassName, subClassIsSubClass, navigator.newNavigatorFork() .navigateToChild(subClassNameToTokenElementMap.get(subClassName)), externalizedClassToContentMap, i18nFacadeName, subClassPackageName, rootPackageName); } } //methods based on properties if (hasProperties) { // for (String propertyName : propertyNameToExampleValueListMap.keySet()) { // String propertyKey = propertyNameToPropertyKeyMap.get(propertyName); List<String> exampleValueList = propertyNameToExampleValueListMap.get(propertyName); // List<String> replacementTokensForExampleValuesNumericPlaceholders = determineReplacementTokensForExampleValues( exampleValueList, "\\{\\d+\\}"); List<String> replacementTokensForExampleValuesArbitraryPlaceholders = determineReplacementTokensForExampleValues( exampleValueList, "\\{\\w+\\}"); boolean containsNumericalReplacementToken = replacementTokensForExampleValuesNumericPlaceholders .size() > 0; boolean containsArbitraryReplacementToken = !containsNumericalReplacementToken && replacementTokensForExampleValuesArbitraryPlaceholders.size() > 0; // { // stringBuilder.append(" /**\n"); stringBuilder.append(" * Similar to {@link #get" + propertyName + "()} for the given {@link Locale}.\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #get" + propertyName + "()\n"); stringBuilder.append(" * @param locale \n"); stringBuilder.append(" */ \n"); stringBuilder.append(" protected String get" + propertyName + "(Locale locale)\n"); stringBuilder.append(" {\n"); stringBuilder.append(" try\n"); stringBuilder.append(" {\n"); stringBuilder.append(" final String key = \"" + propertyKey + "\";\n"); stringBuilder.append(" return " + i18nFacadeName + ".Resource.resourceBasedTranslator.translate( baseName, key, locale );\n"); stringBuilder.append(" }\n"); stringBuilder.append(" catch ( MissingResourceException e )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" if (!this.silentlyIgnoreMissingResourceException)\n"); stringBuilder.append(" {\n"); stringBuilder.append(" throw e;\n"); stringBuilder.append(" }\n"); stringBuilder.append(" return null;\n"); stringBuilder.append(" }\n"); stringBuilder.append(" }\n\n"); // stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns the value of the property key <b>" + propertyKey + "</b> for the predefined {@link Locale}.\n"); printJavaDocPlaceholders(stringBuilder, replacementTokensForExampleValuesArbitraryPlaceholders); printJavaDocValueExamples(stringBuilder, exampleValueList); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String get" + propertyName + "()\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return get" + propertyName + "( this.locale );\n"); stringBuilder.append(" }\n\n"); } // if (containsNumericalReplacementToken) { // stringBuilder.append(" /**\n"); stringBuilder.append(" * Similar to {@link #get" + propertyName + "(Object[])} using the given {@link Locale}.\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #get" + propertyName + "(String[])\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" * @param tokens\n"); stringBuilder.append(" */ \n"); stringBuilder.append( " public String get" + propertyName + "( Locale locale, Object... tokens )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" String retval = get" + propertyName + "( locale );\n"); stringBuilder.append(" for ( int ii = 0; ii < tokens.length; ii++ )\n"); stringBuilder.append(" {\n"); stringBuilder.append( " String token = tokens[ii] != null ? tokens[ii].toString() : null;\n"); stringBuilder.append(" if ( token != null )\n"); stringBuilder.append(" {\n"); stringBuilder.append( " retval = retval.replaceAll( \"\\\\{\" + ii + \"\\\\}\", token );\n"); stringBuilder.append(" }\n"); stringBuilder.append(" }\n"); stringBuilder.append(" return retval;\n"); stringBuilder.append(" }\n\n"); // stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns the value of the property key <b>" + propertyKey + "</b> for the predefined {@link Locale} with all {0},{1},... placeholders replaced by the given tokens in their order.<br><br>\n"); stringBuilder.append( " * If there are not enough parameters existing placeholders will remain unreplaced.\n"); printJavaDocPlaceholders(stringBuilder, replacementTokensForExampleValuesNumericPlaceholders); printJavaDocValueExamples(stringBuilder, exampleValueList); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #get" + propertyName + "(Locale,Object[])\n"); stringBuilder.append(" * @param tokens\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String get" + propertyName + "( Object... tokens )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return get" + propertyName + "( this.locale, tokens );\n"); stringBuilder.append(" }\n\n"); } // if (containsArbitraryReplacementToken) { importSet.add("java.util.Map"); // stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns the value of the property key <b>" + propertyKey + "</b> for the given {@link Locale} with arbitrary placeholder tag like {example} replaced by the given values.<br>\n"); stringBuilder.append( " * The given placeholderToReplacementMap needs the placeholder tag name and a value. E.g. for {example} the key \"example\" has to be set.\n"); printJavaDocPlaceholders(stringBuilder, replacementTokensForExampleValuesArbitraryPlaceholders); printJavaDocValueExamples(stringBuilder, exampleValueList); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #get" + propertyName + "(Map)\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" * @param placeholderToReplacementMap\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String get" + propertyName + "( Locale locale, Map<String, String> placeholderToReplacementMap )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" String retval = get" + propertyName + "( locale );\n"); stringBuilder.append(" if ( placeholderToReplacementMap != null )\n"); stringBuilder.append(" {\n"); stringBuilder.append( " for ( String placeholder : placeholderToReplacementMap.keySet() )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" if ( placeholder != null )\n"); stringBuilder.append(" {\n"); stringBuilder.append( " String token = placeholderToReplacementMap.get( placeholder );\n"); stringBuilder.append( " retval = retval.replaceAll( \"\\\\{\" + placeholder + \"\\\\}\", token );\n"); stringBuilder.append(" }\n"); stringBuilder.append(" }\n"); stringBuilder.append(" }\n"); stringBuilder.append(" return retval;\n"); stringBuilder.append(" }\n\n"); // stringBuilder.append(" /**\n"); stringBuilder.append(" * Similar to {@link #get" + propertyName + "(Locale,Map)} using the predefined {@link Locale}.\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #get" + propertyName + "(Locale,Map)\n"); stringBuilder.append(" * @param placeholderToReplacementMap\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String get" + propertyName + "( Map<String, String> placeholderToReplacementMap )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return get" + propertyName + "( this.locale, placeholderToReplacementMap );\n"); stringBuilder.append(" }\n\n"); } } //fluid factory methods { // stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns a new instance of {@link " + className + "} which uses the given setting for the exception handling\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @param silentlyIgnoreMissingResourceException \n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public " + className + " doSilentlyIgnoreMissingResourceException( boolean silentlyIgnoreMissingResourceException )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return new " + className + "( this.locale, silentlyIgnoreMissingResourceException );\n"); stringBuilder.append(" }\n\n"); // stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns a new instance of {@link " + className + "} which uses the given {@link Locale}\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @param locale \n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public " + className + " forLocale( Locale locale )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return new " + className + "( locale, this.silentlyIgnoreMissingResourceException );\n"); stringBuilder.append(" }\n\n"); } //translator methods { // stringBuilder.append(" /**\n"); stringBuilder.append( " * Returns a new {@link Translator} instance using the given {@link Locale} and based on the {@value #baseName} i18n base\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #translator()\n"); stringBuilder.append(" * @see #translator(Locale)\n"); stringBuilder.append(" * @return {@link Translator}"); stringBuilder.append(" */ \n"); stringBuilder.append( " public static Translator translator(Locale locale, boolean silentlyIgnoreMissingResourceException)\n"); stringBuilder.append(" {\n"); stringBuilder.append( " return new Translator( baseName, locale, silentlyIgnoreMissingResourceException );\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" /**\n"); stringBuilder.append( " * Returns a new {@link Translator} instance using the given {@link Locale} and based on the {@value #baseName} i18n base\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #translator()\n"); stringBuilder.append(" * @see #translator(Locale,boolean)\n"); stringBuilder.append(" * @return {@link Translator}"); stringBuilder.append(" */ \n"); stringBuilder.append(" public Translator translator(Locale locale)\n"); stringBuilder.append(" {\n"); stringBuilder.append( " return new Translator( baseName, locale, this.silentlyIgnoreMissingResourceException );\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" /**\n"); stringBuilder.append( " * Returns a new {@link Translator} instance using the internal {@link Locale} and based on the {@value #baseName} i18n base\n"); stringBuilder.append(" * @see " + className + "\n"); stringBuilder.append(" * @see #translator(Locale)\n"); stringBuilder.append(" * @see #translator(Locale,boolean)\n"); stringBuilder.append(" * @return {@link Translator}"); stringBuilder.append(" */ \n"); stringBuilder.append(" public Translator translator()\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return translator( this.locale );\n"); stringBuilder.append(" }\n\n"); } } } // stringBuilder.append("}\n\n"); StringBuilder importBuf = new StringBuilder(); for (String importDef : importSet) { importBuf.append("import " + importDef + ";\n"); } stringBuilder.insert(importOffset, importBuf.toString() + "\n"); } private static void printJavaDocPropertiesExamplesForSubclassAndInstance(StringBuilder stringBuilder, final Map<String, List<String>> propertyNameToExampleValueListMap, final Map<String, String> propertyNameToPropertyKeyMap) { // stringBuilder.append(" * <br><br>\n"); stringBuilder.append(" * <h1>Examples:</h1>\n"); stringBuilder.append(" * <table border=\"1\">\n"); stringBuilder.append(" * <thead>\n"); stringBuilder.append(" * <tr>\n"); stringBuilder.append(" * <th>key</th>\n"); stringBuilder.append(" * <th>examples</th>\n"); stringBuilder.append(" * </tr>\n"); stringBuilder.append(" * </thead>\n"); stringBuilder.append(" * <tbody>\n"); for (String propertyName : propertyNameToExampleValueListMap.keySet()) { // final int exampleSizeMax = 3; // final String propertyKey = propertyNameToPropertyKeyMap.get(propertyName); final List<String> exampleValueList = new ArrayList<String>( propertyNameToExampleValueListMap.get(propertyName)); { while (exampleValueList.size() > exampleSizeMax) { exampleValueList.remove(exampleValueList.size() - 1); } } final Iterator<String> iteratorExampleValueList = exampleValueList.iterator(); // final int exampleSize = exampleValueList.size(); if (exampleSize > 0) { // stringBuilder.append(" * <tr>\n"); stringBuilder.append(" * <td rowspan=\"" + exampleSize + "\">" + propertyKey + "</td>\n"); stringBuilder.append(" * <td>" + iteratorExampleValueList.next() + "</td>\n"); stringBuilder.append(" * </tr>\n"); while (iteratorExampleValueList.hasNext()) { // stringBuilder.append(" * <tr>\n"); stringBuilder.append(" * <td><small>" + iteratorExampleValueList.next() + "</small></td>\n"); stringBuilder.append(" * </tr>\n"); } } } stringBuilder.append(" * </tbody>\n"); stringBuilder.append(" * </table><br><br>\n"); } private static void appendResourceBasedTranslatorInterface(StringBuilder stringBuilder) { // stringBuilder.append("\n"); stringBuilder.append(" /**\n"); stringBuilder.append( " * Basic interface which is used by the facade to resolve translated values for given keys<br>\n"); stringBuilder.append(" * <br>\n"); stringBuilder.append(" * Any implementation should be thread safe"); stringBuilder.append(" */ \n"); stringBuilder.append(" public static interface ResourceBasedTranslator {\n"); stringBuilder.append(" /**\n"); stringBuilder.append( " * Returns the translated value for the given key respecting the base name and the given {@link Locale}\n"); stringBuilder.append(" * @param baseName\n"); stringBuilder.append(" * @param key\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" * @return\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String translate( String baseName, String key, Locale locale );\n"); stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns all available keys for the given {@link Locale}\n"); stringBuilder.append(" * @param baseName\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" * @return\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String[] resolveAllKeys( String baseName, Locale locale );\n"); stringBuilder.append(" }\n"); stringBuilder.append("\n"); } private static void appendTranslatorHelper(StringBuilder stringBuilder, String I18nFacadeName) { stringBuilder.append("\n"); stringBuilder.append(" /**\n"); stringBuilder.append( " * A {@link Translator} offers several methods to translate arbitrary keys into their i18n counterpart based on the initially\n"); stringBuilder.append(" * given {@link Locale}.\n"); stringBuilder.append(" * \n"); stringBuilder.append(" * @see #translate(String)\n"); stringBuilder.append(" * @see #translate(String[]) \n"); stringBuilder.append(" * @see #allPropertyKeys() \n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public static class Translator {\n"); //translator vars and constructor { stringBuilder.append("\n"); stringBuilder.append(" private final String baseName;\n"); stringBuilder.append(" private final Locale locale;\n"); stringBuilder.append(" private final boolean silentlyIgnoreMissingResourceException;\n"); stringBuilder.append("\n"); stringBuilder.append(" /**\n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @param baseName\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public Translator( String baseName, Locale locale )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" this(baseName,locale,true);\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" /**\n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @param baseName\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" */ \n"); stringBuilder.append( " public Translator( String baseName, Locale locale, boolean silentlyIgnoreMissingResourceException )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" super();\n"); stringBuilder.append(" this.baseName = baseName;\n"); stringBuilder.append(" this.locale = locale;\n"); stringBuilder.append( " this.silentlyIgnoreMissingResourceException = silentlyIgnoreMissingResourceException;\n"); stringBuilder.append(" }\n\n"); } //translation map methods { // stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns the translated property key for the given {@link Locale}\n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #translate(String)\n"); stringBuilder.append(" * @see #translate(String[])\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String translate(Locale locale, String key)\n"); stringBuilder.append(" {\n"); stringBuilder.append(" try\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return " + I18nFacadeName + ".Resource.resourceBasedTranslator.translate( this.baseName, key, locale );\n"); stringBuilder.append(" }\n"); stringBuilder.append(" catch ( MissingResourceException e )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" if (!this.silentlyIgnoreMissingResourceException)\n"); stringBuilder.append(" {\n"); stringBuilder.append(" throw e;\n"); stringBuilder.append(" }\n"); stringBuilder.append(" return null;\n"); stringBuilder.append(" }\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns the translated property key for the predefined {@link Locale}\n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #translate(Locale, String)\n"); stringBuilder.append(" * @see #translate(String[])\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String translate( String key )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return translate( this.locale, key );\n"); stringBuilder.append(" }\n\n"); // stringBuilder.append(" /**\n"); stringBuilder.append( " * Returns a translation {@link Map} with the given property keys and their respective values for the given {@link Locale}.\n"); stringBuilder.append(" * @param keys \n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #allPropertyKeys()\n"); stringBuilder.append(" * @see #translate(String)\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public Map<String, String> translate( Locale locale, String... keys )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" Map<String, String> retmap = new LinkedHashMap<String, String>();\n"); stringBuilder.append(" for ( String key : keys )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" retmap.put( key, translate( locale, key ) );\n"); stringBuilder.append(" }\n"); stringBuilder.append(" return retmap;\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" /**\n"); stringBuilder.append( " * Returns a translation {@link Map} with the given property keys and their respective values for the predefined {@link Locale}.\n"); stringBuilder.append(" * @param keys \n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #allPropertyKeys()\n"); stringBuilder.append(" * @see #translate(String)\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public Map<String, String> translate( String... keys )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return translate( this.locale, keys );\n"); stringBuilder.append(" }\n\n"); // stringBuilder.append(" /**\n"); stringBuilder.append(" * Returns all available property keys for the given {@link Locale}. \n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #allPropertyKeys()\n"); stringBuilder.append(" * @see #translate(String[])\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String[] allPropertyKeys(Locale locale)\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return " + I18nFacadeName + ".Resource.resourceBasedTranslator.resolveAllKeys( this.baseName, locale );\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" /**\n"); stringBuilder .append(" * Returns all available property keys for the predefined {@link Locale}. \n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #allPropertyKeys(Locale)\n"); stringBuilder.append(" * @see #translate(String[])\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public String[] allPropertyKeys()\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return allPropertyKeys( this.locale );\n"); stringBuilder.append(" }\n\n"); // stringBuilder.append(" /**\n"); stringBuilder.append( " * Returns a translation {@link Map} for the predefined {@link Locale} including all available i18n keys resolved using \n"); stringBuilder.append( " * {@link #allPropertyKeys()} and their respective translation values resolved using {@link #translate(String...)} \n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #allPropertyKeys(Locale)\n"); stringBuilder.append(" * @see #translate(String[])\n"); stringBuilder.append(" * @return {@link Map}\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public Map<String, String> translationMap()\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return this.translate( this.allPropertyKeys() );\n"); stringBuilder.append(" }\n\n"); stringBuilder.append(" /**\n"); stringBuilder .append(" * Similar to {@link #translationMap()} for the given {@link Locale} instead. \n"); stringBuilder.append(" * @see Translator\n"); stringBuilder.append(" * @see #allPropertyKeys(Locale)\n"); stringBuilder.append(" * @see #translate(String[])\n"); stringBuilder.append(" * @param locale\n"); stringBuilder.append(" * @return {@link Map}\n"); stringBuilder.append(" */ \n"); stringBuilder.append(" public Map<String, String> translationMap( Locale locale )\n"); stringBuilder.append(" {\n"); stringBuilder.append(" return this.translate( locale, this.allPropertyKeys( locale ) );\n"); stringBuilder.append(" }\n\n"); } // stringBuilder.append(" }\n"); stringBuilder.append("\n"); } private static void printJavaDocPlaceholders(StringBuilder stringBuilder, List<String> replacementTokensForExampleValuesPlaceholders) { stringBuilder.append(" * <br><br>\n"); if (!replacementTokensForExampleValuesPlaceholders.isEmpty()) { stringBuilder.append(" * Placeholders:\n"); stringBuilder.append(" * <ul>\n"); for (String replacementToken : replacementTokensForExampleValuesPlaceholders) { stringBuilder.append(" * <li><b>" + replacementToken + "</b></li>\n"); } stringBuilder.append(" * </ul>\n"); } } /** * @param stringBuilder * @param exampleValueList */ private static void printJavaDocValueExamples(StringBuilder stringBuilder, List<String> exampleValueList) { stringBuilder.append(" * \n"); stringBuilder.append(" * Examples:\n"); stringBuilder.append(" * <ul>\n"); for (String exampleValue : exampleValueList) { stringBuilder.append(" * <li>" + exampleValue + "</li>\n"); } stringBuilder.append(" * </ul>\n"); } /** * @param exampleValueList * @param regexTokenPattern * @return */ private static List<String> determineReplacementTokensForExampleValues(List<String> exampleValueList, String regexTokenPattern) { // Set<String> retset = new LinkedHashSet<String>(); // final Pattern pattern = Pattern.compile(regexTokenPattern); for (String exampleValue : exampleValueList) { Matcher matcher = pattern.matcher(exampleValue); while (matcher.find()) { retset.add(matcher.group()); } } // return new ArrayList<String>(retset); } protected static class CamelCaseTokenElementToMapEntryConverter implements ElementConverterElementToMapEntry<String, String, String> { private static final long serialVersionUID = 1L; /* ********************************************** Variables ********************************************** */ public String excludedkey = null; /* ********************************************** Methods ********************************************** */ public CamelCaseTokenElementToMapEntryConverter(String excludedkey) { super(); this.excludedkey = excludedkey; } @Override public Entry<String, String> convert(String element) { // String key = ""; String value = ""; // if (element != null) { // String[] tokens = element.split("[^a-zA-Z0-9]"); for (String token : tokens) { key += StringUtils.capitalize(token); } // key = StringUtils.isBlank(key) ? "Root" : key; key = key.matches("\\d+.*") ? "_" + key : key; key = StringUtils.equals(key, this.excludedkey) ? key + "_" : key; // value = element; } // return new SimpleEntry<String, String>(key, value); } } }