org.carrot2.util.attribute.AttributeValueSets.java Source code

Java tutorial

Introduction

Here is the source code for org.carrot2.util.attribute.AttributeValueSets.java

Source

/*
 * Carrot2 project.
 *
 * Copyright (C) 2002-2015, Dawid Weiss, Stanisaw Osiski.
 * All rights reserved.
 *
 * Refer to the full license file "carrot2.LICENSE"
 * in the root folder of the repository checkout or at:
 * http://www.carrot2.org/carrot2.LICENSE
 */

package org.carrot2.util.attribute;

import java.io.*;
import java.util.*;

import org.simpleframework.xml.ElementMap;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.core.*;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * Maintains a collection of {@link AttributeValueSet}s and provides methods for
 * serializing and deserializing attribute value sets from XML streams.
 */
@Root(name = "attribute-sets")
public class AttributeValueSets {
    @ElementMap(name = "attribute-sets", entry = "attribute-set", key = "id", inline = true, attribute = true, required = false)
    Map<String, AttributeValueSet> attributeValueSets;

    @org.simpleframework.xml.Attribute(name = "default", required = false)
    String defaultAttributeValueSetId;

    /**
     * Creates an empty collection of attribute value sets.
     */
    public AttributeValueSets() {
        this.attributeValueSets = Maps.newLinkedHashMap();
    }

    /**
     * Adds an {@link AttributeValueSet} to this collection.
     * 
     * @param id unique identifier of the {@link AttributeValueSet} within the collection.
     * @param attributeValueSet {@link AttributeValueSet} to be added
     */
    public void addAttributeValueSet(String id, AttributeValueSet attributeValueSet) {
        if (attributeValueSets.containsKey(id)) {
            throw new IllegalArgumentException("Attribute value set with id=" + id + " already exists");
        }

        attributeValueSets.put(id, attributeValueSet);
    }

    /**
     * Adds an {@link AttributeValueSet} to this collection replacing its label and
     * description. This method may sometimes be useful because {@link AttributeValueSet}s
     * are immutable with respect to their label and description.
     * 
     * @param id unique identifier of the {@link AttributeValueSet} within the collection.
     * @param attributeValueSet {@link AttributeValueSet} to be added
     * @param newLabel new label for the {@link AttributeValueSet}
     * @param newDescription new description for the {@link AttributeValueSet}
     */
    public void addAttributeValueSet(String id, AttributeValueSet attributeValueSet, String newLabel,
            String newDescription) {
        final AttributeValueSet newAttributeValueSet = new AttributeValueSet(newLabel, newDescription,
                attributeValueSet.baseAttributeValueSet);
        newAttributeValueSet.overridenAttributeValues.putAll(attributeValueSet.overridenAttributeValues);

        addAttributeValueSet(id, newAttributeValueSet);
    }

    /**
     * Returns identifiers of all {@link AttributeValueSet}s in this collection.
     * 
     * @return identifiers of all {@link AttributeValueSet}s in this collection.
     */
    public Set<String> getAttributeValueSetIds() {
        return attributeValueSets.keySet();
    }

    /**
     * Returns the identifier of the default {@link AttributeValueSet} within this
     * {@link AttributeValueSets}. The default identifier can be <code>null</code>.
     */
    public String getDefaultAttributeValueSetId() {
        return defaultAttributeValueSetId;
    }

    /**
     * Sets the default attribute value set id for this {@link AttributeValueSets}. An
     * {@link AttributeValueSet} with this id must exist in this
     * {@link AttributeValueSets}.
     */
    public void setDefaultAttributeValueSetId(String defaultAttributeValueSetId) {
        if (defaultAttributeValueSetId != null && !attributeValueSets.containsKey(defaultAttributeValueSetId)) {
            throw new IllegalArgumentException(
                    "Attribute value set with id: " + defaultAttributeValueSetId + " does not exist.");
        }
        this.defaultAttributeValueSetId = defaultAttributeValueSetId;
    }

    /**
     * Returns the {@link AttributeValueSet} corresponding to the provided <code>id</code>
     * or <code>null</code> if no {@link AttributeValueSet} corresponds to the
     * <code>id</code>.
     * 
     * @return the {@link AttributeValueSet} corresponding to the provided <code>id</code>
     *         or <code>null</code> if no {@link AttributeValueSet} corresponds to the
     *         <code>id</code>.
     */
    public AttributeValueSet getAttributeValueSet(String id) {
        return getAttributeValueSet(id, false);
    }

    /**
     * Returns the {@link AttributeValueSet} corresponding to the provided <code>id</code>
     * or the default {@link AttributeValueSet} (possibly <code>null</code>) if no
     * {@link AttributeValueSet} corresponds to the <code>id</code>.
     * 
     * @param id identifier of the {@link AttributeValueSet} to return
     * @param useDefault if <code>true</code>, the default {@link AttributeValueSet} will
     *            be returned if the {@link AttributeValueSet} with the provided id does
     *            not exist.
     * @return the {@link AttributeValueSet} corresponding to the provided <code>id</code>
     *         or the default {@link AttributeValueSet} (possibly <code>null</code>) if no
     *         {@link AttributeValueSet} corresponds to the <code>id</code>.
     */
    public AttributeValueSet getAttributeValueSet(String id, boolean useDefault) {
        if (attributeValueSets.containsKey(id)) {
            return attributeValueSets.get(id);
        } else {
            return (useDefault ? getDefaultAttributeValueSet() : null);
        }
    }

    /**
     * Returns the default {@link AttributeValueSet} of this {@link AttributeValueSets} or
     * the first available {@link AttributeValueSet} if
     * {@link #getDefaultAttributeValueSetId()} is <code>null</code>. If this
     * {@link AttributeValueSets} is empty, <code>null</code> will be returned.
     */
    public AttributeValueSet getDefaultAttributeValueSet() {
        AttributeValueSet result = null;
        if (defaultAttributeValueSetId != null) {
            result = getAttributeValueSet(defaultAttributeValueSetId);
        }

        // Try the first attribute set
        if (result == null) {
            final Iterator<AttributeValueSet> iterator = attributeValueSets.values().iterator();
            if (iterator.hasNext()) {
                result = iterator.next();
            }
        }

        return result;
    }

    /**
     * Removes the {@link AttributeValueSet} corresponding to the provided <code>id</code>
     * from this collection. If any other {@link AttributeValueSet}s in this collection
     * are based on the set being removed, the associations are corrected accordingly,
     * i.e. sets based on the set being removed become based on the set the removed set is
     * based on. Also, if the removed {@link AttributeValueSet} was the default,
     * <code>null</code> will be set as this {@link AttributeValueSets}' default
     * {@link AttributeValueSet}. If no {@link AttributeValueSet} corresponds to the
     * provided <code>id</code>, no action is taken.
     * 
     * @param id identifier of the {@link AttributeValueSet} to be removed
     */
    public void removeAttributeValueSet(String id) {
        final AttributeValueSet attributeValueSet = attributeValueSets.get(id);
        if (attributeValueSet == null) {
            return;
        }

        attributeValueSets.remove(id);

        // Also, we need to fix the "based on" hierarchy here
        final AttributeValueSet newBaseAttributeValueSet = attributeValueSet.baseAttributeValueSet;
        for (final AttributeValueSet set : attributeValueSets.values()) {
            set.baseAttributeValueSet = newBaseAttributeValueSet;
        }

        if (id.equals(defaultAttributeValueSetId)) {
            defaultAttributeValueSetId = null;
        }
    }

    /**
     * Returns all {@link AttributeValueSet}s from this collection that are based,
     * directly or indirectly, on the provided <code>baseAttributeValueSet</code>.
     * 
     * @param baseAttributeValueSet the base attribute value set
     */
    public Set<AttributeValueSet> getAttributeValueSetsBasedOn(AttributeValueSet baseAttributeValueSet) {
        final Set<AttributeValueSet> result = Sets.newHashSet();
        for (final AttributeValueSet set : attributeValueSets.values()) {
            if (set.baseAttributeValueSet == baseAttributeValueSet) {
                result.add(set);
                result.addAll(getAttributeValueSetsBasedOn(set));
            }
        }

        return result;
    }

    /**
     * Updates base attribute value set ids before persisting.
     */
    @Persist
    @SuppressWarnings("unused")
    private void updateBaseAttributeValueSetIds() {
        // There won't be too many attribute values sets, so nested loops should be fine
        outer: for (final AttributeValueSet attributeValueSet : attributeValueSets.values()) {
            if (attributeValueSet.baseAttributeValueSet == null) {
                continue;
            }

            for (final Map.Entry<String, AttributeValueSet> entry : attributeValueSets.entrySet()) {
                if (attributeValueSet.baseAttributeValueSet == entry.getValue()) {
                    attributeValueSet.baseAttributeValueSetId = entry.getKey();
                    continue outer;
                }
            }
        }
    }

    /**
     * Restores base attribute value set references based on ids on deserialization.
     */
    @Commit
    @SuppressWarnings("unused")
    private void restoreBaseAttributeValueSets() {
        for (final AttributeValueSet attributeValueSet : attributeValueSets.values()) {
            attributeValueSet.baseAttributeValueSet = attributeValueSets
                    .get(attributeValueSet.baseAttributeValueSetId);
        }
    }

    /**
     * Serializes this collection of {@link AttributeValueSet}s to an XML stream.
     * 
     * @param stream the stream to serialize this {@link AttributeValueSets} to. The stream
     *            will <strong>not</strong> be closed.
     * @throws Exception in case of any problems with serialization
     */
    public void serialize(OutputStream stream) throws Exception {
        new Persister().write(this, stream);
    }

    /**
     * Deserializes a collection of {@link AttributeValueSet}s from an XML stream.
     * 
     * @param inputStream the {@link InputStream} to deserialize a
     *            {@link AttributeValueSets} from. The stream will <strong>not</strong> be
     *            closed.
     * @return Deserialized collection of {@link AttributeValueSet}s
     * @throws Exception is case of any problems with deserialization.
     */
    public static AttributeValueSets deserialize(InputStream inputStream) throws Exception {
        final AttributeValueSets attributeValueSet = new Persister().read(AttributeValueSets.class, inputStream);

        checkDefaultAttributeValueSetExists(attributeValueSet);

        return attributeValueSet;
    }

    private static void checkDefaultAttributeValueSetExists(final AttributeValueSets attributeValueSet) {
        if (attributeValueSet.defaultAttributeValueSetId != null && !attributeValueSet.attributeValueSets
                .containsKey(attributeValueSet.defaultAttributeValueSetId)) {
            throw new RuntimeException(
                    "Default attribute value set not found: " + attributeValueSet.defaultAttributeValueSetId);
        }
    }

    /*
     * 
     */
    @Override
    public String toString() {
        return "AttributeValueSet [set IDs: " + Arrays.toString(this.getAttributeValueSetIds().toArray()) + "]";
    }
}