com.isotrol.impe3.pms.core.obj.PortalConfigurationObject.java Source code

Java tutorial

Introduction

Here is the source code for com.isotrol.impe3.pms.core.obj.PortalConfigurationObject.java

Source

/**
 * This file is part of Port@l
 * Port@l 3.0 - Portal Engine and Management System
 * Copyright (C) 2010  Isotrol, SA.  http://www.isotrol.com
 *
 * Port@l is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Port@l 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Port@l.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.isotrol.impe3.pms.core.obj;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.io.ByteStreams.toByteArray;
import static com.isotrol.impe3.pms.core.obj.Builders.add;
import static com.isotrol.impe3.pms.core.obj.Builders.build;
import static com.isotrol.impe3.pms.core.obj.Builders.put;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;

import org.slf4j.Logger;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.protobuf.ByteString;
import com.isotrol.impe3.api.AbstractIdentifiable;
import com.isotrol.impe3.api.Category;
import com.isotrol.impe3.api.ContentType;
import com.isotrol.impe3.api.FileData;
import com.isotrol.impe3.api.FileId;
import com.isotrol.impe3.api.PortalConfiguration;
import com.isotrol.impe3.core.ImpeIAModel;
import com.isotrol.impe3.core.Loggers;
import com.isotrol.impe3.core.config.PortalConfigurationBuilder;
import com.isotrol.impe3.core.config.PortalConfigurationDefinition;
import com.isotrol.impe3.core.config.PortalConfigurationDefinition.Item;
import com.isotrol.impe3.core.support.NamedSupport;
import com.isotrol.impe3.pbuf.BaseProtos.ConfigurationPB;
import com.isotrol.impe3.pbuf.BaseProtos.ConfigurationValuePB;
import com.isotrol.impe3.pbuf.BaseProtos.FileContentPB;
import com.isotrol.impe3.pms.api.PMSException;
import com.isotrol.impe3.pms.api.config.ChoiceItemDTO;
import com.isotrol.impe3.pms.api.config.ConfigurationItemType;
import com.isotrol.impe3.pms.api.config.ConfigurationTemplateDTO;
import com.isotrol.impe3.pms.api.config.ConfigurationTemplateItemDTO;
import com.isotrol.impe3.pms.api.config.UploadedFileDTO;
import com.isotrol.impe3.pms.core.FileManager;
import com.isotrol.impe3.pms.core.support.AbstractValueLoader;
import com.isotrol.impe3.pms.core.support.Mappers;
import com.isotrol.impe3.pms.model.CategoryEntity;
import com.isotrol.impe3.pms.model.ComponentDfn;
import com.isotrol.impe3.pms.model.ConfigurationEntity;
import com.isotrol.impe3.pms.model.ConfigurationValue;
import com.isotrol.impe3.pms.model.ContentTypeEntity;
import com.isotrol.impe3.pms.model.FileEntity;
import com.isotrol.impe3.pms.model.PortalConfigurationValue;
import com.isotrol.impe3.pms.model.WithModuleDfn;

/**
 * Portal configuration domain object.
 * @author Enrique Diaz
 */
public final class PortalConfigurationObject extends AbstractIdentifiable {
    private static final String LOG_PREFIX = "Configuration [{}] type [{}]: ";
    private static final ImmutableMap<Class<?>, ConfigurationItemType> TYPES = ImmutableMap
            .<Class<?>, ConfigurationItemType>builder().put(String.class, ConfigurationItemType.STRING)
            .put(Integer.class, ConfigurationItemType.INTEGER).put(FileId.class, ConfigurationItemType.FILE)
            .put(ContentType.class, ConfigurationItemType.CONTENT_TYPE)
            .put(Category.class, ConfigurationItemType.CATEGORY).put(Boolean.class, ConfigurationItemType.BOOLEAN)
            .build();

    private static Object[] logArgs(PortalConfigurationObject object, Object o) {
        return new Object[] { object.getStringId(), object.definition.getType().getName(), o };
    }

    private static final Function<Item, ConfigurationTemplateItemDTO> item(final Context1 ctx,
            final PortalConfigurationObject object) {
        return new Function<Item, ConfigurationTemplateItemDTO>() {
            public ConfigurationTemplateItemDTO apply(Item from) {
                final ConfigurationTemplateItemDTO dto = new ConfigurationTemplateItemDTO();
                dto.setKey(from.getParameter());
                Mappers.named2described(from, dto, ctx.getLocale());
                dto.setRequired(from.isRequired());
                dto.setType(getType(from));
                dto.setStringStyle(from.getStringStyle());
                final Object defaultValue = from.getDefaultValue();
                final Object value = (object == null) ? null : object.values.get(from.getParameter());
                if (value == null && defaultValue != null) {
                    switch (dto.getType()) {
                    case CHOICE:
                        dto.setChoice(((Enum<?>) defaultValue).name());
                        break;
                    case STRING:
                        dto.setString((String) defaultValue);
                        break;
                    case INTEGER:
                        dto.setInteger((Integer) defaultValue);
                        break;
                    case BOOLEAN:
                        dto.setBoolean((Boolean) defaultValue);
                        break;
                    default:
                        break;
                    }
                } else if (value != null) {
                    try {
                        switch (dto.getType()) {
                        case CHOICE:
                            dto.setChoice(((Enum<?>) value).name());
                            break;
                        case STRING:
                            dto.setString((String) value);
                            break;
                        case INTEGER:
                            dto.setInteger((Integer) value);
                            break;
                        case FILE:
                            final FileId fid = (FileId) value;
                            final UploadedFileDTO uf = new UploadedFileDTO();
                            uf.setId(fid.getStringId());
                            uf.setName(fid.getName());
                            dto.setFile(uf);
                            dto.setBundle(from.isBundle());
                            break;
                        case CONTENT_TYPE:
                            dto.setContentType(checkNotNull(ctx.getContentTypes().get((UUID) value)).toSelDTO());
                            break;
                        case CATEGORY:
                            dto.setCategory(checkNotNull(ctx.getCategories().get((UUID) value)).toSelDTO());
                            break;
                        case BOOLEAN:
                            dto.setBoolean((Boolean) value);
                            break;
                        default:
                            break;
                        }
                    } catch (RuntimeException e) {
                        Loggers.pms().error(LOG_PREFIX + "Unable to load item",
                                logArgs(object, from.getParameter()));
                        throw e;
                    }
                }
                if (from.isEnum()) {
                    Map<Enum<?>, NamedSupport> choices = from.getChoices();
                    List<ChoiceItemDTO> list = Lists.newArrayListWithCapacity(choices.size());
                    for (Entry<Enum<?>, NamedSupport> choice : choices.entrySet()) {
                        ChoiceItemDTO c = new ChoiceItemDTO();
                        c.setKey(choice.getKey().name());
                        Mappers.named2described(choice.getValue(), c, ctx.getLocale());
                        list.add(c);
                    }
                    dto.setChoices(list);
                }
                return dto;
            }
        };
    }

    private static ConfigurationItemType getType(Item item) {
        if (item.isEnum()) {
            return ConfigurationItemType.CHOICE;
        }
        return TYPES.get(item.getType());
    }

    /** Object loader. */
    private static final Loader LOADER = new Loader();

    /**
     * Creates a new configuration object.
     * @param definition Configuration definition.
     * @param dfn Configuration entity.
     * @return A configuration object or {@code null} if any of the arguments is {@code null}.
     */
    static PortalConfigurationObject of(PortalConfigurationDefinition<?> definition, WithModuleDfn dfn) {
        if (definition == null || dfn == null) {
            return null;
        }

        // Si es componente, leemos la configuracion por portal
        if (ComponentDfn.class.isAssignableFrom(dfn.getClass())) {
            PortalConfigurationValue value = ((ComponentDfn) dfn).getComponent().getPortal().getCurrent()
                    .getPortalConfiguration().get(definition.getType().getName());
            return value != null ? LOADER.get(value.getPortalConfiguration(), definition) : null;
        }

        return null;
    }

    /**
     * Creates a new configuration object.
     * @param definition Configuration definition.
     * @param dfn Configuration entity.
     * @return A configuration object or {@code null} if any of the arguments is {@code null}.
     */
    public static PortalConfigurationObject of(PortalConfigurationDefinition<?> definition,
            ConfigurationEntity entity) {
        if (definition == null || entity == null) {
            return null;
        }

        // Si es componente, leemos la configuracion por portal
        return LOADER.get(entity, definition);
    }

    private static ConfigurationTemplateDTO create(PortalConfigurationDefinition<?> definition, Context1 ctx,
            PortalConfigurationObject object) {
        final ConfigurationTemplateDTO dto = new ConfigurationTemplateDTO();
        dto.setKey(definition.getType().getName());
        if (definition.hasContentTypes()) {
            dto.setContentTypes(ctx.getContentTypes().map2sel());
        }
        if (definition.hasCategories()) {
            dto.setCategories(ctx.getCategories().map2tree());
        }
        final Locale locale = ctx.getLocale();
        Mappers.named2described(definition, dto, locale);
        dto.setItems(Mappers.list(definition.getParameters().values(), item(ctx, object)));
        return dto;
    }

    static ConfigurationTemplateDTO template(PortalConfigurationDefinition<?> definition, Context1 ctx) {
        final ConfigurationTemplateDTO dto = create(definition, ctx, null);
        return dto;
    }

    /** Configuration definition. */
    private final PortalConfigurationDefinition<?> definition;
    /** Configuration values. */
    private final ImmutableMap<String, Object> values;
    /** Used content types. */
    private final ImmutableSet<UUID> usedContentTypes;
    /** Used categories. */
    private final ImmutableSet<UUID> usedCategories;
    /** Exported files. */
    private final ImmutableMap<UUID, PortalFileObject> files;
    /** Errors: Missing required parameters or incorrect values. */
    private final ImmutableSet<String> errors;
    /** Extra parameters. */
    private final ImmutableSet<String> extra;

    /**
     * Constructor.
     * @param definition Definition.
     * @param entity Configuration entity.
     */
    private PortalConfigurationObject(PortalConfigurationDefinition<?> definition, ConfigurationEntity entity) {
        super(entity.getId());
        ImmutableMap.Builder<String, Object> values = null;
        ImmutableMap.Builder<UUID, PortalFileObject> files = null;
        ImmutableSet.Builder<UUID> usedContentTypes = null;
        ImmutableSet.Builder<UUID> usedCategories = null;
        ImmutableSet.Builder<String> extra = null;
        ImmutableSet.Builder<String> errors = null;
        final ImmutableMap<String, Item> parameters = definition.getParameters();
        for (Entry<String, ConfigurationValue> ecv : entity.getValues().entrySet()) {
            final String name = ecv.getKey();
            final Item item = parameters.get(name);
            if (item == null) {
                extra = add(extra, name);
                continue;
            }
            final Class<?> type = item.getType();
            Object value = null;
            final ConfigurationValue cv = ecv.getValue();
            if (item.isEnum()) {
                try {
                    value = item.fromString(cv.getStringValue());
                } catch (IllegalArgumentException iae) {
                    if (errors == null) {
                        errors = ImmutableSet.builder();
                    }
                    errors.add(name);
                }

            } else if (String.class == type) {
                value = cv.getStringValue();
            } else if (Integer.class == type) {
                value = cv.getIntegerValue();
            } else if (Boolean.class == type) {
                value = cv.getBooleanValue();
            } else if (FileId.class == type) {
                final FileEntity fe = cv.getFileValue();
                if (fe != null) {
                    final UUID id = fe.getId();
                    final FileId fid = FileId.of(id, fe.getName());
                    value = fid;
                    files = put(files, id, new PortalFileObject(fid, item));
                }
            } else if (Category.class == type) {
                final CategoryEntity ce = cv.getCategoryValue();
                if (ce != null) {
                    final UUID id = ce.getId();
                    value = id;
                    usedCategories = add(usedCategories, id);
                }
            } else if (ContentType.class == type) {
                final ContentTypeEntity ce = cv.getContentTypeValue();
                if (ce != null) {
                    final UUID id = ce.getId();
                    value = id;
                    usedContentTypes = add(usedContentTypes, id);
                }
            }
            if (value != null) {
                values = put(values, name, value);
            }
        }
        this.definition = definition;
        this.values = build(values);
        this.files = build(files);
        this.usedContentTypes = build(usedContentTypes);
        this.usedCategories = build(usedCategories);
        Set<String> missing = Sets.difference(definition.getMBPParameters().keySet(), this.values.keySet());
        if (errors == null) {
            this.errors = ImmutableSet.copyOf(missing);
        } else {
            this.errors = errors.addAll(missing).build();
        }
        this.extra = build(extra);
    }

    public boolean isError() {
        return !errors.isEmpty();
    }

    public boolean isWarning() {
        return isError() || !extra.isEmpty();
    }

    private Object[] logArgs(Object o) {
        return new Object[] { getStringId(), definition.getType().getName(), o };
    }

    public void log(Logger logger) {
        if (!extra.isEmpty() && logger.isWarnEnabled()) {
            logger.warn(LOG_PREFIX + "Unused saved parameters: ", logArgs(extra));
        }
        if (!errors.isEmpty() && logger.isErrorEnabled()) {
            logger.warn(LOG_PREFIX + "Missing required parameters: ", logArgs(errors));
        }
    }

    PortalConfiguration get(ImpeIAModel model) {
        checkState(!isError(), "Invalid configuration state");
        final PortalConfigurationBuilder<?> cb = definition.builder();
        final ImmutableMap<String, Item> parameters = definition.getParameters();
        for (Entry<String, Object> ecv : values.entrySet()) {
            final String name = ecv.getKey();
            final Class<?> type = parameters.get(name).getType();
            final Object value = ecv.getValue();
            try {
                if (Category.class == type) {
                    cb.set(name, checkNotNull(model.getCategories().get((UUID) value)));
                } else if (ContentType.class == type) {
                    cb.set(name, checkNotNull(model.getContentTypes().get((UUID) value)));
                } else {
                    cb.set(name, value);
                }
            } catch (RuntimeException e) {
                Loggers.pms().error(LOG_PREFIX + "Error setting parameter [{}]", logArgs(name));
                throw e;
            }
        }
        try {
            return cb.get();
        } catch (RuntimeException e) {
            Loggers.pms().error(LOG_PREFIX + "Unable to build configuration", logArgs(null));
            throw e;
        }
    }

    /**
     * Returns whether a content type is used by this configuration.
     * @param id Content type id.
     * @return True if the content type is used by this configuration.
     */
    public boolean isContentTypeUsed(UUID id) {
        return usedContentTypes.contains(id);
    }

    /**
     * Returns whether a category is used by this configuration.
     * @param id Category id.
     * @return True if the category is used by this configuration.
     */
    public boolean isCategoryUsed(UUID id) {
        return usedCategories.contains(id);
    }

    public ImmutableMap<UUID, PortalFileObject> getFiles() {
        return files;
    }

    public ConfigurationTemplateDTO toTemplateDTO(Context1 ctx) {
        return create(definition, ctx, this);
    }

    /**
     * Transforms the object to a protocol buffer message.
     * @param fileManager Required in order to recover file content.
     * @return The PB message.
     */
    final ConfigurationPB toPB(FileManager fileManager) {
        ConfigurationPB.Builder b = ConfigurationPB.newBuilder();

        final ImmutableMap<String, Item> parameters = definition.getParameters();

        for (Entry<String, Item> entry : parameters.entrySet()) {
            final Item item = entry.getValue();
            if (item != null) {
                final String name = entry.getKey();
                b.addConfigurationValues(configurationValuePB(name, item, fileManager));
            }
        }

        return b.build();
    }

    private ConfigurationValuePB configurationValuePB(String name, Item item, FileManager fileManager) {
        ConfigurationValuePB.Builder b = ConfigurationValuePB.newBuilder();
        b.setName(name);

        final Class<?> type = item.getType();

        if (item.isEnum()) {
            final Enum<?> value = (Enum<?>) values.get(name);
            if (value != null) {
                b.setCtString(value.name());
            }
        } else if (String.class == type) {
            final String value = (String) values.get(name);
            if (value != null) {
                b.setCtString(value);
            }
        } else if (Integer.class == type) {
            final Integer value = (Integer) values.get(name);
            if (value != null) {
                b.setCtInteger(value);
            }
        } else if (Boolean.class == type) {
            final Boolean value = (Boolean) values.get(name);
            if (value != null) {
                b.setCtBoolean(value);
            }
        } else if (FileId.class == type) {
            if (fileManager != null) {
                final FileId value = (FileId) values.get(name);
                if (value != null) {
                    try {
                        FileContentPB.Builder fileBuilder = FileContentPB.newBuilder();
                        FileData data = fileManager.getFile(value.getStringId());

                        fileBuilder.setName(data.getName());

                        fileBuilder.setContent(ByteString.copyFrom(toByteArray(data.getData())));

                        b.setCtFile(fileBuilder);
                    } catch (PMSException e) {
                    } catch (IOException e) {
                    }
                }
            }
        } else if (Category.class == type) {
            final UUID value = (UUID) values.get(name);
            if (value != null) {
                b.setCtString(value.toString());
            }
        } else if (ContentType.class == type) {
            final UUID value = (UUID) values.get(name);
            if (value != null) {
                b.setCtString(value.toString());
            }
        }

        return b.build();
    }

    private static final class Loader extends
            AbstractValueLoader<ConfigurationEntity, PortalConfigurationObject, PortalConfigurationDefinition<?>> {
        Loader() {
            super("Configuration");
        }

        @Override
        protected PortalConfigurationObject load(ConfigurationEntity entity,
                PortalConfigurationDefinition<?> definition) {
            return new PortalConfigurationObject(definition, entity);
        }
    }

}