org.omnaest.i18nbinder.internal.FacadeCreatorHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.omnaest.i18nbinder.internal.FacadeCreatorHelper.java

Source

/*******************************************************************************
 * 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);
        }

    }
}