de.iew.services.impl.MessageBundleServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for de.iew.services.impl.MessageBundleServiceImpl.java

Source

/*
 * Copyright 2012 Manuel Schulze <manuel_schulze@i-entwicklung.de>
 *
 * 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.iew.services.impl;

import de.iew.framework.domain.MessageBundle;
import de.iew.framework.domain.MessageBundleStore;
import de.iew.framework.domain.TextItem;
import de.iew.framework.i18n.LocaleUtils;
import de.iew.framework.persistence.MessageBundleDao;
import de.iew.services.MessageBundleService;
import de.iew.services.UnsupportedBasenameException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;

/**
 * Implementiert einen Dienst fr die Verwaltung von MessageBundles.
 * <p>
 * Untersttzt:
 * </p>
 * <ul>
 * <li>Verwaltung der Sprachinhalte in einem Datenbackend</li>
 * <li>Abgleichen von Sprachdateien (Properties-Dateien) in das Datenbackend</li>
 * <li>Implementiert {@link org.springframework.context.MessageSource} und kann daher als MessageSource verwendet werden</li>
 * <li>Optionales Caching der Sprachinhalte</li>
 * </ul>
 *
 * @author Manuel Schulze <manuel_schulze@i-entwicklung.de>
 * @since 25.11.12 - 03:25
 */
public class MessageBundleServiceImpl extends AbstractMessageSource
        implements MessageBundleService, ResourceLoaderAware, InitializingBean {

    private static final Log log = LogFactory.getLog(MessageBundleServiceImpl.class);

    private Locale defaultLocale;

    private ResourceLoader resourceLoader;

    private String[] messageBundles = new String[0];

    private MessageBundleDao messageBundleDao;

    private String cacheName = "java.text.MessageFormat";

    private CacheManager cacheManager;

    private volatile List<Locale> supportedLocales;

    public boolean isSupportedBasename(String basename) {
        this.messageBundleDao.getSupportedLocales();
        if (basename == null) {
            return true;
        }
        for (String check : this.messageBundles) {
            if (check.indexOf(basename) != -1) {
                return true;
            }
        }

        return false;
    }

    /*
    Hier reicht synchronized auf diesem Objekt, da wir nix im Cache
    speichern sondern nur lokal als Objektvariable. Jedes Exemplar des
    MessageBundleCache hat somit auch ein eigenes Exemplar.
     */
    public synchronized List<Locale> getSupportedLocales() {
        if (this.supportedLocales == null) {
            this.supportedLocales = this.messageBundleDao.getSupportedLocales();
        }
        return this.supportedLocales;
    }

    public MessageBundleStore getMessageBundle(Locale locale, String basename) throws UnsupportedBasenameException {
        if (!isSupportedBasename(basename)) {
            throw new UnsupportedBasenameException(
                    "A MessageBundle with basename " + basename + " is not supported.");
        }
        MessageBundleStore messageBundleStore;

        synchronized (MessageBundleService.class) {
            messageBundleStore = getBundleFromCache(locale, basename);
            if (messageBundleStore == null) {
                if (log.isTraceEnabled()) {
                    log.trace("Cache MISS: MessageBundle fr Cache Key " + messageBundleKey(locale, basename)
                            + " nicht im Cache. Lade aus Datenbank!!!");
                }
                messageBundleStore = loadBundle(locale, basename);
                putBundleIntoCach(messageBundleStore, basename);
            }
        }

        return messageBundleStore;
    }

    public MessageBundleStore getDefaultMessageBundle(String basename) throws UnsupportedBasenameException {
        return getMessageBundle(this.defaultLocale, basename);
    }

    protected MessageBundleStore loadBundle(Locale locale, String basename) {
        List<MessageBundle> messageBundles;
        if (basename == null) {
            messageBundles = this.messageBundleDao.findByLocale(locale.getLanguage(), locale.getCountry());
        } else {
            messageBundles = this.messageBundleDao.findByLocaleAndBasename(locale.getLanguage(),
                    locale.getCountry(), basename);
        }

        MessageBundleStore messageBundleStore = new MessageBundleStore(locale, basename);
        for (MessageBundle messageBundle : messageBundles) {
            messageBundleStore.put(messageBundle);
        }

        return messageBundleStore;
    }

    protected MessageBundleStore getBundleFromCache(Locale locale, String basename) {
        MessageBundleStore messageBundleStore = null;
        String cacheKey = messageBundleKey(locale, basename);

        Cache cache = this.cacheManager.getCache(this.cacheName);
        if (cache != null) {
            Cache.ValueWrapper value = cache.get(cacheKey);
            if (value != null) {
                if (log.isTraceEnabled()) {
                    log.trace("Cache HIT: MessageBundle fr Cache Key " + cacheKey + " im Cache vorhanden.");
                }
                messageBundleStore = (MessageBundleStore) value.get();
            }
        }
        return messageBundleStore;
    }

    protected void putBundleIntoCach(MessageBundleStore messageBundleStore, String basename) {
        Cache cache = this.cacheManager.getCache(this.cacheName);
        if (cache != null) {
            String cacheKey = messageBundleKey(messageBundleStore.getLanguageCode(),
                    messageBundleStore.getCountryCode(), basename);
            cache.put(cacheKey, messageBundleStore);
        }
    }

    protected String messageBundleKey(Locale locale, String basename) {
        return messageBundleKey(locale.getLanguage(), locale.getCountry(), basename);
    }

    protected String messageBundleKey(String languageCode, String countryCode, String basename) {
        if (basename == null || basename.length() == 0) {
            return languageCode + "_" + countryCode;
        } else {
            return basename + "_" + languageCode + "_" + countryCode;
        }
    }

    @Override
    protected MessageFormat resolveCode(String code, Locale locale) {
        MessageFormat mf = null;
        try {
            MessageBundleStore messageBundleStore = getMessageBundle(locale, null);
            if (messageBundleStore == null || !messageBundleStore.contains(code)) {
                messageBundleStore = getDefaultMessageBundle(null);
            }

            String message = messageBundleStore.get(code);
            if (message != null) {
                mf = new MessageFormat(message);
            }
        } catch (UnsupportedBasenameException e) {
            if (log.isErrorEnabled()) {
                log.error("Fehler beim Auflsen des Message-Key " + code + ".", e);
            }
        }
        return mf;
    }

    public void synchronizeMessageBundles() throws IOException {
        for (String messageBundle : this.messageBundles) {
            if (!messageBundle.endsWith(".properties")) {
                messageBundle += ".properties";
            }
            loadMessageBundle(messageBundle);
        }
    }

    public void loadMessageBundle(String source) throws IOException {
        Resource resource = this.resourceLoader.getResource(source);

        String basename = resource.getFile().getName();
        if (basename.endsWith(".properties")) {
            basename = basename.substring(0, basename.length() - ".properties".length());
        }

        if (log.isDebugEnabled()) {
            log.debug("Basisname der zu importierenden Datei " + basename + ".");
        }

        Properties properties = new Properties();
        properties.load(resource.getInputStream());

        loadMessageBundle(properties, basename);
    }

    public void loadMessageBundle(Properties messageBundle, String bundleIdentifier) throws IOException {
        Locale locale = this.defaultLocale;

        String[] components = LocaleUtils.extractLocaleComponents(bundleIdentifier);
        if (components.length == 3) {
            bundleIdentifier = components[0];
            locale = new Locale(components[1], components[2]);
        }

        loadMessageBundle(messageBundle, bundleIdentifier, locale);
    }

    public void loadMessageBundle(Properties messageBundle, String basename, Locale locale) {
        if (log.isDebugEnabled()) {
            log.debug("Synchronisiere MessageBundle " + basename + " fr Locale " + locale + ".");
        }

        MessageBundle mb;
        for (String messageKey : messageBundle.stringPropertyNames()) {
            if (log.isTraceEnabled()) {
                log.trace(messageKey + " -> " + messageBundle.getProperty(messageKey));
            }
            mb = this.messageBundleDao.findByTextKeyAndLocale(messageKey, locale.getLanguage(),
                    locale.getCountry());
            if (mb == null) {
                TextItem textItem = new TextItem();
                textItem.setLanguageCode(locale.getLanguage());
                textItem.setCountryCode(locale.getCountry());
                textItem.setContent(messageBundle.getProperty(messageKey));

                mb = new MessageBundle();
                mb.setTextKey(messageKey);
                mb.setBasename(basename);
                mb.setTextItem(textItem);

                this.messageBundleDao.save(mb);
            }
        }
    }

    public void afterPropertiesSet() throws Exception {
        synchronizeMessageBundles();
    }

    public void setMessageBundles(String[] messageBundles) {
        this.messageBundles = messageBundles;
    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Value(value = "#{config['locale.default']}")
    public void setDefaultLocale(Locale defaultLocale) {
        this.defaultLocale = defaultLocale;
    }

    @Autowired
    public void setMessageBundleDao(MessageBundleDao messageBundleDao) {
        this.messageBundleDao = messageBundleDao;
    }

    @Autowired
    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
}