Package org.restlet.representation

Source Code of org.restlet.representation.Variant

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.representation;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.restlet.data.CharacterSet;
import org.restlet.data.ClientInfo;
import org.restlet.data.Encoding;
import org.restlet.data.Language;
import org.restlet.data.MediaType;
import org.restlet.data.Preference;
import org.restlet.data.Reference;
import org.restlet.util.WrapperList;

/**
* Descriptor for available representations of a resource. It contains all the
* important metadata about a representation but is not able to actually serve
* the representation's content itself.<br>
* <br>
* For this, you need to use the Representation subclass.
*
* @author Jerome Louvel
*/
public class Variant {

    /** The character set or null if not applicable. */
    private volatile CharacterSet characterSet;

    /** The additional content codings applied to the entity-body. */
    private volatile List<Encoding> encodings;

    /** The location reference. */
    private volatile Reference locationRef;

    /** The natural language(s) of the intended audience for this variant. */
    private volatile List<Language> languages;

    /** The media type. */
    private volatile MediaType mediaType;

    /**
     * Default constructor.
     */
    public Variant() {
        this(null);
    }

    /**
     * Constructor.
     *
     * @param mediaType
     *            The media type.
     */
    public Variant(MediaType mediaType) {
        this(mediaType, null);
    }

    /**
     * Constructor.
     *
     * @param mediaType
     *            The media type.
     * @param language
     *            The language.
     */
    public Variant(MediaType mediaType, Language language) {
        this.characterSet = null;
        this.encodings = null;

        if (language != null) {
            getLanguages().add(language);
        } else {
            this.languages = null;
        }

        this.mediaType = mediaType;
        this.locationRef = null;
    }

    /**
     * Creates a {@link ClientInfo} instance with preferences matching exactly
     * the current variant.
     *
     * @return The new {@link ClientInfo} instance.
     */
    public ClientInfo createClientInfo() {
        ClientInfo result = new ClientInfo();

        if (getCharacterSet() != null) {
            result.getAcceptedCharacterSets().add(
                    new Preference<CharacterSet>(getCharacterSet()));
        }

        if (getEncodings() != null) {
            for (Encoding encoding : getEncodings()) {
                result.getAcceptedEncodings().add(
                        new Preference<Encoding>(encoding));
            }
        }

        if (getLanguages() != null) {
            for (Language language : getLanguages()) {
                result.getAcceptedLanguages().add(
                        new Preference<Language>(language));
            }
        }

        if (getMediaType() != null) {
            result.getAcceptedMediaTypes().add(
                    new Preference<MediaType>(getMediaType()));
        }

        return result;
    }

    /**
     * Indicates if the current variant is equal to the given variant.
     *
     * @param other
     *            The other variant.
     * @return True if the current variant includes the other.
     */
    @Override
    public boolean equals(Object other) {
        boolean result = (other instanceof Variant);

        if (result && (other != this)) {
            Variant otherVariant = (Variant) other;

            // Compare the character set
            if (result) {
                result = ((getCharacterSet() == null)
                        && (otherVariant.getCharacterSet() == null) || (getCharacterSet() != null)
                        && getCharacterSet().equals(
                                otherVariant.getCharacterSet()));
            }

            // Compare the media type
            if (result) {
                result = ((getMediaType() == null)
                        && (otherVariant.getMediaType() == null) || (getMediaType() != null)
                        && getMediaType().equals(otherVariant.getMediaType()));
            }

            // Compare the languages
            if (result) {
                result = getLanguages().equals(otherVariant.getLanguages());
            }

            // Compare the encodings
            if (result) {
                result = getEncodings().equals(otherVariant.getEncodings());
            }

            // Compare the location URI
            if (result) {
                result = ((getLocationRef() == null)
                        && (otherVariant.getLocationRef() == null) || (getLocationRef() != null)
                        && getLocationRef().equals(
                                otherVariant.getLocationRef()));
            }
        }

        return result;
    }

    /**
     * Returns the character set or null if not applicable. Note that when used
     * with HTTP connectors, this property maps to the "Content-Type" header.
     *
     * @return The character set or null if not applicable.
     */
    public CharacterSet getCharacterSet() {
        return this.characterSet;
    }

    /**
     * Returns the modifiable list of encodings applied to the entity-body.
     * Creates a new instance if no one has been set. An
     * "IllegalArgumentException" exception is thrown when adding a null
     * encoding to this list.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Encoding" header.
     *
     * @return The list of encodings applied to the entity-body.
     */
    public List<Encoding> getEncodings() {
        if (this.encodings == null) {
            this.encodings = new WrapperList<Encoding>() {

                @Override
                public boolean add(Encoding element) {
                    if (element == null) {
                        throw new IllegalArgumentException(
                                "Cannot add a null encoding.");
                    }

                    return super.add(element);
                }

                @Override
                public void add(int index, Encoding element) {
                    if (element == null) {
                        throw new IllegalArgumentException(
                                "Cannot add a null encoding.");
                    }

                    super.add(index, element);
                }

                @Override
                public boolean addAll(Collection<? extends Encoding> elements) {
                    boolean addNull = (elements == null);
                    if (!addNull) {
                        for (final Iterator<? extends Encoding> iterator = elements
                                .iterator(); !addNull && iterator.hasNext();) {
                            addNull = (iterator.next() == null);
                        }
                    }
                    if (addNull) {
                        throw new IllegalArgumentException(
                                "Cannot add a null encoding.");
                    }

                    return super.addAll(elements);
                }

                @Override
                public boolean addAll(int index,
                        Collection<? extends Encoding> elements) {
                    boolean addNull = (elements == null);
                    if (!addNull) {
                        for (final Iterator<? extends Encoding> iterator = elements
                                .iterator(); !addNull && iterator.hasNext();) {
                            addNull = (iterator.next() == null);
                        }
                    }
                    if (addNull) {
                        throw new IllegalArgumentException(
                                "Cannot add a null encoding.");
                    }

                    return super.addAll(index, elements);
                }
            };
        }

        return this.encodings;
    }

    /**
     * Returns the modifiable list of languages. Creates a new instance if no
     * one has been set. An "IllegalArgumentException" exception is thrown when
     * adding a null language to this list.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Language" header.
     *
     * @return The list of languages.
     */
    public List<Language> getLanguages() {
        if (this.languages == null) {
            this.languages = new WrapperList<Language>() {

                @Override
                public void add(int index, Language element) {
                    if (element == null) {
                        throw new IllegalArgumentException(
                                "Cannot add a null language.");
                    }

                    super.add(index, element);
                }

                @Override
                public boolean add(Language element) {
                    if (element == null) {
                        throw new IllegalArgumentException(
                                "Cannot add a null language.");
                    }

                    return super.add(element);
                }

                @Override
                public boolean addAll(Collection<? extends Language> elements) {
                    boolean addNull = (elements == null);
                    if (!addNull) {
                        for (final Iterator<? extends Language> iterator = elements
                                .iterator(); !addNull && iterator.hasNext();) {
                            addNull = (iterator.next() == null);
                        }
                    }
                    if (addNull) {
                        throw new IllegalArgumentException(
                                "Cannot add a null language.");
                    }

                    return super.addAll(elements);
                }

                @Override
                public boolean addAll(int index,
                        Collection<? extends Language> elements) {
                    boolean addNull = (elements == null);
                    if (!addNull) {
                        for (final Iterator<? extends Language> iterator = elements
                                .iterator(); !addNull && iterator.hasNext();) {
                            addNull = (iterator.next() == null);
                        }
                    }
                    if (addNull) {
                        throw new IllegalArgumentException(
                                "Cannot add a null language.");
                    }

                    return super.addAll(index, elements);
                }

            };
        }
        return this.languages;
    }

    /**
     * Returns an optional location reference. This is useful when the
     * representation is accessible from a location separate from the
     * representation's resource URI, for example when content negotiation
     * occurs.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Location" header.
     *
     * @return The identifier.
     */
    public Reference getLocationRef() {
        return this.locationRef;
    }

    /**
     * Returns the media type.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Type" header.
     *
     * @return The media type.
     */
    public MediaType getMediaType() {
        return this.mediaType;
    }

    /**
     * Indicates if the current variant includes the given variant.
     *
     * @param other
     *            The other variant.
     * @return True if the current variant includes the other.
     */
    public boolean includes(Variant other) {
        boolean result = other != null;

        // Compare the character set
        if (result) {
            result = (getCharacterSet() == null)
                    || getCharacterSet().includes(other.getCharacterSet());
        }

        // Compare the media type
        if (result) {
            result = (getMediaType() == null)
                    || getMediaType().includes(other.getMediaType());
        }

        // Compare the languages
        if (result) {
            result = (getLanguages().isEmpty())
                    || getLanguages().contains(Language.ALL)
                    || getLanguages().containsAll(other.getLanguages());
        }

        // Compare the encodings
        if (result) {
            result = (getEncodings().isEmpty())
                    || getEncodings().contains(Encoding.ALL)
                    || getEncodings().containsAll(other.getEncodings());
        }

        return result;
    }

    /**
     * Indicates if the current variant is compatible with the given variant.
     *
     * @param other
     *            The other variant.
     * @return True if the current variant is compatible with the other.
     */
    public boolean isCompatible(Variant other) {
        return (other != null) && (includes(other) || other.includes(this));
    }

    /**
     * Sets the character set or null if not applicable.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Type" header.
     *
     * @param characterSet
     *            The character set or null if not applicable.
     */
    public void setCharacterSet(CharacterSet characterSet) {
        this.characterSet = characterSet;
    }

    /**
     * Sets the list of encodings applied to the entity-body.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Encoding" header.
     *
     * @param encodings
     *            The list of encodings applied to the entity-body.
     */
    public void setEncodings(List<Encoding> encodings) {
        this.encodings = encodings;
    }

    /**
     * Sets the list of languages.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Language" header.
     *
     * @param languages
     *            The list of languages.
     */
    public void setLanguages(List<Language> languages) {
        this.languages = languages;
    }

    /**
     * Sets the optional identifier. This is useful when the representation is
     * accessible from a location separate from the representation's resource
     * URI, for example when content negotiation occurs.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Location" header.
     *
     * @param location
     *            The location reference.
     */
    public void setLocationRef(Reference location) {
        this.locationRef = location;
    }

    /**
     * Sets the identifier from a URI string.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Location" header.
     *
     * @param locationUri
     *            The location URI to parse.
     */
    public void setLocationRef(String locationUri) {
        setLocationRef(new Reference(locationUri));
    }

    /**
     * Sets the media type.<br>
     * <br>
     * Note that when used with HTTP connectors, this property maps to the
     * "Content-Type" header.
     *
     * @param mediaType
     *            The media type.
     */
    public void setMediaType(MediaType mediaType) {
        this.mediaType = mediaType;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[");
        boolean first = true;

        if (getMediaType() != null) {
            first = false;
            sb.append(getMediaType());
        }

        if (getCharacterSet() != null) {
            if (!first) {
                sb.append(",");
            } else {
                first = false;
            }

            sb.append(getCharacterSet());
        }

        if (!getLanguages().isEmpty()) {
            if (!first) {
                sb.append(",");
            } else {
                first = false;
            }

            sb.append(getLanguages());
        }

        if (!getEncodings().isEmpty()) {
            if (!first) {
                sb.append(",");
            } else {
                first = false;
            }

            sb.append(getEncodings());
        }

        sb.append("]");
        return sb.toString();
    }
}
TOP

Related Classes of org.restlet.representation.Variant

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.