org.mayocat.localization.internal.DefaultEntityLocalizationService.java Source code

Java tutorial

Introduction

Here is the source code for org.mayocat.localization.internal.DefaultEntityLocalizationService.java

Source

/*
 * Copyright (c) 2012, Mayocat <hello@mayocat.org>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.mayocat.localization.internal;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.inject.Inject;

import org.apache.commons.lang3.SerializationUtils;
import org.mayocat.attachment.model.LoadedAttachment;
import org.mayocat.context.WebContext;
import org.mayocat.localization.EntityLocalizationService;
import org.mayocat.model.AddonGroup;
import org.mayocat.attachment.model.Attachment;
import org.mayocat.attachment.model.AttachmentData;
import org.mayocat.model.Entity;
import org.mayocat.model.HasAddons;
import org.mayocat.model.Localized;
import org.mayocat.model.annotation.LocalizedField;
import org.xwiki.component.annotation.Component;

import com.google.common.base.Strings;

/**
 * @version $Id: 5c0656391234ebf2ac507e8f75583e69eb305553 $
 */
@Component
public class DefaultEntityLocalizationService implements EntityLocalizationService {
    @Inject
    private org.slf4j.Logger logger;

    @Inject
    private WebContext context;

    @Override
    public <T extends Localized> T localize(T entity) {
        if (this.context == null || !this.context.isAlternativeLocale()) {
            return entity;
        } else {
            return localize(entity, this.context.getLocale());
        }
    }

    @Override
    public <T extends Localized> T localize(T entity, Locale locale) {
        if (locale == null || entity.getLocalizedVersions() == null
                || !entity.getLocalizedVersions().containsKey(locale)) {
            return entity;
        }

        T copiedEntity = SerializationUtils.clone(entity);

        if (copiedEntity == null) {
            return entity;
        }

        // Special I/O case for loaded attachment : set back the input stream manually
        if (copiedEntity instanceof LoadedAttachment) {
            ((LoadedAttachment) copiedEntity)
                    .setData(new AttachmentData(((LoadedAttachment) entity).getData().getStream()));
        }

        // Handle entity fields :
        // - loops over methods, checking for setters, then for each one of them
        // - infer a field name from found setter
        // - check if that field has a "LocalizedField" annotation, if not ignore
        // - if it does, try to find this field in the locale's map of translations
        // - if found and not null or empty string use the setter to set this as the localized field value

        for (Method method : copiedEntity.getClass().getDeclaredMethods()) {
            if (method.getName().startsWith("set") && Character.isUpperCase(method.getName().charAt(3))) {
                // Found a setter.
                if (method.getName().length() <= 4) {
                    continue;
                }
                String fieldName = method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4);

                Field field = null;
                try {
                    field = copiedEntity.getClass().getDeclaredField(fieldName);
                } catch (NoSuchFieldException e) {
                    this.logger.debug("Cannot find field for setter {}", method.getName());
                }

                // Check if either field or method has a "LocalizedField" annotation
                if (field != null && (field.isAnnotationPresent(LocalizedField.class)
                        || method.isAnnotationPresent(LocalizedField.class))) {
                    Object value = null;
                    if (copiedEntity.getLocalizedVersions().get(locale).containsKey(fieldName)) {

                        value = copiedEntity.getLocalizedVersions().get(locale).get(fieldName);

                        if (String.class.isAssignableFrom(value.getClass())
                                && Strings.isNullOrEmpty((String) value)) {
                            // Ignore empty strings, consider them as nulls
                            continue;
                        }

                        boolean setterAccessible = method.isAccessible();
                        method.setAccessible(true);
                        try {
                            method.invoke(copiedEntity, value);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            logger.error("Cannot set property {}", field.getName());
                        }

                        method.setAccessible(setterAccessible);
                    }
                }
            }
        }

        // Handle entity addons :
        // - check if entity has addons and those addons are loaded, and the localized version contains something
        // for addons
        // - if yes, then loop over all the entity addons, and for each :
        // - try to find the equivalent addon in the map of translation
        // - if found, and its value is not null or empty string, replace the addon value by the localized one

        if (hasLoadedAddons(copiedEntity)
                && copiedEntity.getLocalizedVersions().get(locale).containsKey("addons")) {
            Map<String, AddonGroup> entityAddons = ((HasAddons) copiedEntity).getAddons().get();
            final Map<String, Object> localizedAddons = (Map<String, Object>) copiedEntity.getLocalizedVersions()
                    .get(locale).get("addons");

            for (AddonGroup addon : entityAddons.values()) {
                if (localizedAddons.containsKey(addon.getGroup())) {
                    Map<String, Object> localizedGroup = (Map<String, Object>) localizedAddons
                            .get(addon.getGroup());

                    if (Map.class.isAssignableFrom(addon.getValue().getClass())) {

                        // Non-sequence addons

                        Map<String, Object> value = (Map<String, Object>) addon.getValue();
                        Map<String, Object> localizedGroupValue = (Map<String, Object>) localizedGroup.get("value");

                        for (String field : value.keySet()) {
                            Object localizedValue = localizedGroupValue.get(field);

                            if (localizedValue == null || (String.class.isAssignableFrom(localizedValue.getClass())
                                    && Strings.isNullOrEmpty((String) localizedValue))) {
                                // Ignore empty strings, consider them as nulls
                                continue;
                            }

                            ((Map<String, Object>) addon.getValue()).put(field, localizedValue);
                        }
                    } else if (List.class.isAssignableFrom(addon.getValue().getClass())) {

                        // Sequence addons

                        List<Map<String, Object>> values = (List<Map<String, Object>>) addon.getValue();
                        try {
                            List<Map<String, Object>> localizedGroupValue = (List<Map<String, Object>>) localizedGroup
                                    .get("value");
                            Integer i = 0;
                            for (Map<String, Object> value : values) {
                                Map<String, Object> localizedGroupValueItem = localizedGroupValue.get(i);

                                for (String field : value.keySet()) {
                                    Object localizedValue = localizedGroupValueItem.get(field);

                                    if (localizedValue == null
                                            || (String.class.isAssignableFrom(localizedValue.getClass())
                                                    && Strings.isNullOrEmpty((String) localizedValue))) {
                                        // Ignore empty strings, consider them as nulls
                                        continue;
                                    }

                                    ((List<Map<String, Object>>) addon.getValue()).get(i).put(field,
                                            localizedValue);
                                }
                                i++;
                            }
                        } catch (ClassCastException e) {
                            // Ignore...
                        }
                    }
                }
            }
        }

        return copiedEntity;
    }

    private boolean hasLoadedAddons(Entity entity) {
        return HasAddons.class.isAssignableFrom(entity.getClass()) && ((HasAddons) entity).getAddons().isLoaded();
    }

}