de.perdian.commons.i18n.polyglot.PolyglotImpl.java Source code

Java tutorial

Introduction

Here is the source code for de.perdian.commons.i18n.polyglot.PolyglotImpl.java

Source

/*
 * Copyright 2013 Christian Robert
 *
 * 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 de.perdian.commons.i18n.polyglot;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;

import org.springframework.context.MessageSource;

import de.perdian.commons.i18n.polyglot.annotations.PolyglotConfiguration;
import de.perdian.commons.i18n.polyglot.annotations.PolyglotDefault;
import de.perdian.commons.i18n.polyglot.annotations.PolyglotKey;

class PolyglotImpl<T> implements Polyglot<T> {

    private final Map<Locale, T> localeToInstanceCache = new HashMap<>();
    private Class<T> instanceClass = null;
    private MessageSource messageSource = null;

    @Override
    public T getInstance(Locale locale) {
        if (locale == null) {
            throw new IllegalArgumentException("Parameter 'locale' must not be null");
        } else {
            T cachedInstance = this.getLocaleToInstanceCache().get(locale);
            if (cachedInstance == null) {
                Class<T> instanceClass = this.getInstanceClass();
                cachedInstance = instanceClass.cast(Proxy.newProxyInstance(instanceClass.getClassLoader(),
                        new Class[] { instanceClass }, this.createInvocationHandler(locale)));
                this.getLocaleToInstanceCache().put(locale, cachedInstance);
            }
            return cachedInstance;
        }
    }

    private InvocationHandler createInvocationHandler(Locale locale) {
        PolyglotInvocationHandler invocationHandler = new PolyglotInvocationHandler();
        invocationHandler.setLocale(locale);
        invocationHandler.setMessageSource(this.getMessageSource());
        invocationHandler.setInfoMap(this.createInvocationInfoMap());
        return invocationHandler;
    }

    private Map<Method, PolyglotInvocationInfo> createInvocationInfoMap() {

        PolyglotConfiguration configuration = this.getInstanceClass().getAnnotation(PolyglotConfiguration.class);
        PolyglotKeyGenerator keyGenerator = new PolyglotKeyGenerator();
        keyGenerator
                .setPrefix(Optional.ofNullable(configuration).map(PolyglotConfiguration::keyPrefix).orElse(null));
        keyGenerator
                .setPostfix(Optional.ofNullable(configuration).map(PolyglotConfiguration::keyPostfix).orElse(null));

        Map<Method, PolyglotInvocationInfo> resultMap = new HashMap<>();
        this.appendInvocationInfos(resultMap, this.getInstanceClass(), keyGenerator);
        return resultMap;

    }

    private void appendInvocationInfos(Map<Method, PolyglotInvocationInfo> resultMap, Class<?> interfaceClass,
            PolyglotKeyGenerator keyGenerator) {
        Class<?>[] implementedInterfaces = interfaceClass.getInterfaces();
        if (implementedInterfaces != null) {
            for (Class<?> implementedInterface : implementedInterfaces) {
                this.appendInvocationInfos(resultMap, implementedInterface, keyGenerator);
            }
        }
        StringBuilder exceptionCollectionString = new StringBuilder();
        Method[] interfaceMethods = interfaceClass.getMethods();
        if (interfaceMethods != null) {
            for (Method interfaceMethod : interfaceMethods) {
                try {
                    resultMap.put(interfaceMethod, this.createInvocationInfo(interfaceMethod, keyGenerator));
                } catch (Exception e) {
                    exceptionCollectionString.append("\n- ").append(interfaceMethod.getName());
                    exceptionCollectionString.append(": ").append(e.getMessage());
                }
            }
            if (exceptionCollectionString.length() > 0) {
                StringBuilder exceptionString = new StringBuilder();
                exceptionString.append("Analyzation of polyglot information for class '").append(interfaceClass)
                        .append("' ");
                exceptionString.append("failed:").append(exceptionCollectionString);
                throw new IllegalArgumentException(exceptionString.toString());
            }
        }
    }

    private PolyglotInvocationInfo createInvocationInfo(Method interfaceMethod, PolyglotKeyGenerator keyGenerator) {
        Class<?> returnType = interfaceMethod.getReturnType();
        if (!returnType.isAssignableFrom(String.class)) {
            throw new IllegalArgumentException("Return type '" + returnType.getName()
                    + "' is not compatible to result type '" + String.class.getName() + "'");
        } else {

            PolyglotKey polyglotKey = interfaceMethod.getAnnotation(PolyglotKey.class);
            String interfaceKey = polyglotKey == null ? interfaceMethod.getName() : polyglotKey.value();
            PolyglotDefault polyglotDefault = interfaceMethod.getAnnotation(PolyglotDefault.class);

            PolyglotInvocationInfo invocationInfo = new PolyglotInvocationInfo();
            invocationInfo.setDefaultValue(polyglotDefault == null ? null : polyglotDefault.value());
            invocationInfo.setKey(keyGenerator.generateKey(interfaceKey));
            return invocationInfo;

        }
    }

    // ---------------------------------------------------------------------------
    // --- Meta creation
    // ---------------------------------------------------------
    // ---------------------------------------------------------------------------

    @Override
    public PolyglotMeta getMeta(Locale locale) {
        if (locale == null) {
            throw new IllegalArgumentException("Parameter 'locale' must not be null");
        } else {
            PolyglotMeta metaImpl = new PolyglotMeta(locale);
            Map<Method, PolyglotInvocationInfo> invocationMap = this.createInvocationInfoMap();
            for (Map.Entry<Method, PolyglotInvocationInfo> invocationEntry : invocationMap.entrySet()) {

                PolyglotInvocationInfo invocationInfo = invocationEntry.getValue();
                String localizedValue = this.getMessageSource().getMessage(invocationInfo.getKey(), null,
                        invocationInfo.getDefaultValue(), locale);
                if (localizedValue == null || localizedValue.length() <= 0) {
                    metaImpl.addMissingValueKey(invocationInfo.getKey());
                }
                metaImpl.addKey(invocationInfo.getKey());

            }
            return metaImpl;
        }
    }

    // -------------------------------------------------------------------------
    // --- Inner classes -------------------------------------------------------
    // -------------------------------------------------------------------------

    static class PolyglotKeyGenerator {

        private String prefix = null;
        private String postfix = null;

        String generateKey(String key) {
            StringBuilder result = new StringBuilder();
            result.append(Optional.ofNullable(this.getPrefix()).orElse(""));
            result.append(key);
            result.append(Optional.ofNullable(this.getPostfix()).orElse(""));
            return result.toString();
        }

        String getPrefix() {
            return this.prefix;
        }

        void setPrefix(String prefix) {
            this.prefix = prefix;
        }

        String getPostfix() {
            return this.postfix;
        }

        void setPostfix(String postfix) {
            this.postfix = postfix;
        }

    }

    // -------------------------------------------------------------------------
    // --- Property access methods ---------------------------------------------
    // -------------------------------------------------------------------------

    Map<Locale, T> getLocaleToInstanceCache() {
        return this.localeToInstanceCache;
    }

    Class<T> getInstanceClass() {
        return this.instanceClass;
    }

    void setInstanceClass(Class<T> instanceClass) {
        this.instanceClass = instanceClass;
    }

    MessageSource getMessageSource() {
        return this.messageSource;
    }

    void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

}