org.squashtest.tm.web.internal.controller.audittrail.RequirementAuditEventTableModelBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.squashtest.tm.web.internal.controller.audittrail.RequirementAuditEventTableModelBuilder.java

Source

/**
 *     This file is part of the Squashtest platform.
 *     Copyright (C) 2010 - 2016 Henix, henix.fr
 *
 *     See the NOTICE file distributed with this work for additional
 *     information regarding copyright ownership.
 *
 *     This is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     this software is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with this software.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.squashtest.tm.web.internal.controller.audittrail;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.util.HtmlUtils;
import org.squashtest.tm.core.foundation.i18n.Internationalizable;
import org.squashtest.tm.domain.event.RequirementAuditEvent;
import org.squashtest.tm.domain.event.RequirementAuditEventVisitor;
import org.squashtest.tm.domain.event.RequirementCreation;
import org.squashtest.tm.domain.event.RequirementLargePropertyChange;
import org.squashtest.tm.domain.event.RequirementPropertyChange;
import org.squashtest.tm.domain.event.RequirementVersionModification;
import org.squashtest.tm.domain.event.SyncRequirementCreation;
import org.squashtest.tm.domain.event.SyncRequirementUpdate;
import org.squashtest.tm.domain.infolist.InfoListItem;
import org.squashtest.tm.domain.requirement.RequirementVersion;
import org.squashtest.tm.web.internal.i18n.InternationalizationHelper;
import org.squashtest.tm.web.internal.model.datatable.DataTableModelBuilder;

/**
 * Builder for datatable model showing {@link RequirementAuditEvent} objects. Not threadsafe, should be discarded after
 * use.
 *
 * @author Gregory Fouquet
 *
 */
public class RequirementAuditEventTableModelBuilder extends DataTableModelBuilder<RequirementAuditEvent>
        implements RequirementAuditEventVisitor {
    /**
     * The locale to use to format the labels.
     */
    private final Locale locale;
    /**
     * The source for localized label messages.
     */
    private final InternationalizationHelper i18nHelper;

    /**
     * Data for the item currently build.
     */
    private Map<String, String> currentItemData;

    /**
     * @param locale
     * @param  messageSource
     */
    public RequirementAuditEventTableModelBuilder(@NotNull Locale locale,
            @NotNull InternationalizationHelper messageSource) {
        super();
        this.i18nHelper = messageSource;
        this.locale = locale;
    }

    /**
     * @see org.squashtest.tm.web.internal.model.datatable.DataTableModelBuilder#buildItemData(java.lang.Object)
     */
    @Override
    protected Map<String, String> buildItemData(RequirementAuditEvent item) {
        item.accept(this);

        return currentItemData;
    }

    /**
     * @see org.squashtest.tm.domain.event.RequirementAuditEventVisitor#visit(org.squashtest.tm.domain.event.RequirementCreation)
     */
    @Override
    public void visit(RequirementCreation event) {
        String message = i18nHelper.internationalize("label.Creation", locale);
        populateCurrentItemData(message, "creation", event);
    }

    @Override
    public void visit(SyncRequirementCreation event) {
        String message = i18nHelper.internationalize("label.CreationBySynchronization", locale);
        populateCurrentItemData(message, "sync-creation", event);
        currentItemData.put("event-meta", event.getSource());

    }

    @Override
    public void visit(SyncRequirementUpdate event) {
        String message = i18nHelper.internationalize("label.UpdateBySynchronization", locale);
        populateCurrentItemData(message, "sync-update", event);
        currentItemData.put("event-meta", event.getSource());
    }

    /**
     * @see org.squashtest.tm.domain.event.RequirementAuditEventVisitor#visit(org.squashtest.tm.domain.event.RequirementPropertyChange)
     */
    @Override
    public void visit(RequirementPropertyChange event) {
        Object[] args = buildMessageArgs(event);

        @SuppressWarnings("deprecation")
        String message = i18nHelper.getMessage(buildPropertyChangeMessageKey(event), args, locale);
        populateCurrentItemData(message, "simple-prop", event);
    }

    private String buildPropertyChangeMessageKey(RequirementVersionModification event) {
        return "message.property-change." + event.getPropertyName() + ".label";
    }

    private Object[] buildMessageArgs(RequirementPropertyChange event) {
        Object[] args;

        if (propertyIsEnumeratedAndInternationalizable(event)) {
            args = buildMessageArgsForI18nableEnumProperty(event);
        } else if (propertyIsInfolist(event)) {
            args = buildMessageArgsForI18ableInfoListProperty(event);
        } else {
            args = buildMessageArgsForStringProperty(event);
        }

        return args;
    }

    private boolean propertyIsEnumeratedAndInternationalizable(RequirementPropertyChange event) {
        Field field = ReflectionUtils.findField(RequirementVersion.class, event.getPropertyName());
        Class<?> fieldType = field.getType();

        return Enum.class.isAssignableFrom(fieldType) && Internationalizable.class.isAssignableFrom(fieldType);
    }

    private boolean propertyIsInfolist(RequirementPropertyChange event) {
        Field field = ReflectionUtils.findField(RequirementVersion.class, event.getPropertyName());
        Class<?> fieldType = field.getType();

        return InfoListItem.class.isAssignableFrom(fieldType);

    }

    private Object[] buildMessageArgsForStringProperty(RequirementPropertyChange event) {
        return new Object[] { event.getOldValue(), event.getNewValue() };
    }

    private Object[] buildMessageArgsForI18nableEnumProperty(RequirementPropertyChange event) {
        Field enumField = ReflectionUtils.findField(RequirementVersion.class, event.getPropertyName());
        Class<?> enumType = enumField.getType();

        String oldValueLabel = retrieveEnumI18ndLabel(enumType, event.getOldValue());
        String newValueLabel = retrieveEnumI18ndLabel(enumType, event.getNewValue());

        return new Object[] { oldValueLabel, newValueLabel };
    }

    /*
     * Unfortunately there is no way to tell which subtype of InfoListItem is being processed there : 
     * the SystemListItem is i18nable while the UserListItem is not. So let's hope for the best : 
     * the i18nhelper should return the key itself if not found in the messagesource
     */
    private Object[] buildMessageArgsForI18ableInfoListProperty(RequirementPropertyChange event) {

        return new Object[] { i18nHelper.getMessage(event.getOldValue(), null, event.getOldValue(), locale),
                i18nHelper.getMessage(event.getNewValue(), null, event.getNewValue(), locale) };
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private String retrieveEnumI18ndLabel(Class enumType, String stringValue) {
        Internationalizable enumValue = (Internationalizable) Enum.valueOf(enumType, stringValue);
        return i18nHelper.internationalize(enumValue, locale);
    }

    /**
     * @see org.squashtest.tm.domain.event.RequirementAuditEventVisitor#visit(org.squashtest.tm.domain.event.RequirementLargePropertyChange)
     */
    @Override
    public void visit(RequirementLargePropertyChange event) {
        String message = i18nHelper.internationalize(buildPropertyChangeMessageKey(event), locale);
        populateCurrentItemData(message, "fat-prop", event);

    }

    private void populateCurrentItemData(String message, String eventType, RequirementAuditEvent event) {

        String formattedDate = DateFormatUtils.format(event.getDate(), "dd/MM/yyyy HH'h'mm");
        String escapedAuthor = HtmlUtils.htmlEscape(event.getAuthor());
        String escapedMessage = HtmlUtils.htmlEscape(message);

        Map<String, String> row = new HashMap<>(5);

        row.put("event-date", formattedDate);
        row.put("event-author", escapedAuthor);
        row.put("event-message", escapedMessage);
        row.put("event-type", eventType);
        row.put("event-id", String.valueOf(event.getId()));

        currentItemData = row;

    }
}