com.lyndir.lhunath.snaplog.data.object.media.Media.java Source code

Java tutorial

Introduction

Here is the source code for com.lyndir.lhunath.snaplog.data.object.media.Media.java

Source

/*
 *   Copyright 2009, Maarten Billemont
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package com.lyndir.lhunath.snaplog.data.object.media;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Objects;
import com.lyndir.lhunath.opal.system.i18n.MessagesFactory;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.snaplog.model.service.WebUtil;
import com.lyndir.lhunath.snaplog.security.SSecureObject;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.HashSet;
import java.util.Set;
import org.joda.time.Instant;
import org.joda.time.ReadableInstant;
import org.joda.time.format.*;

/**
 * <h2>{@link Media}<br> <sub>DO for .</sub></h2>
 *
 * <p> <i>Jul 25, 2009</i> </p>
 *
 * @author lhunath
 */
public abstract class Media extends SSecureObject<Source> implements Comparable<Media> {

    private static final Logger logger = Logger.get(Media.class);
    private static final Messages msgs = MessagesFactory.create(Messages.class);

    private static final transient DateTimeFormatter filenameFormat = ISODateTimeFormat.basicDateTimeNoMillis();

    private final String name;
    private final Set<Tag> tags = new HashSet<Tag>();

    /**
     * @param name The unique name of this media in the source.
     */
    protected Media(final String name) {

        // TODO: Should media be decoupled from source and get its own owner?
        this.name = checkNotNull(name, "Given media name must not be null.");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Source getParent() {

        return getSource();
    }

    /**
     * @return The name of this {@link Media}.
     */
    public String getName() {

        return name;
    }

    /**
     * @return The tags that this media is tagged with.
     */
    public Set<Tag> getTags() {

        return tags;
    }

    /**
     * @return The source of this {@link Media}.
     */
    public abstract Source getSource();

    /**
     * Obtain the time since the UNIX Epoch in milliseconds since the picture was taken.
     *
     * @return The amount of milliseconds, or 0 if it could not be determined.
     */
    public ReadableInstant shotTime() {

        StringBuffer shotTimeString = new StringBuffer(getName());

        // Trim the extension off the filename.
        int extensionIndex = shotTimeString.lastIndexOf(".");
        if (extensionIndex > 0)
            shotTimeString.delete(extensionIndex, shotTimeString.length());

        // Trim the "hidden file prefix" off the filename.
        while (shotTimeString.charAt(0) == '.')
            shotTimeString.deleteCharAt(0);

        // Trim "_extras" off the filename.
        int extraIndex = shotTimeString.lastIndexOf("_");
        if (extraIndex > 0)
            shotTimeString.delete(extraIndex, shotTimeString.length());

        // No time zone == UTC.
        if (shotTimeString.indexOf("+") < 0 && shotTimeString.indexOf("-") < 0)
            shotTimeString.append("+0000");

        try {
            return filenameFormat.parseDateTime(shotTimeString.toString());
        }

        catch (IllegalArgumentException e) {
            logger.wrn(e, "Couldn't parse shot time: %s, for file: %s", shotTimeString, name);

            return new Instant(0);
        }
    }

    /**
     * Generate a string to express the time at which the shot was taken; formatted according to the active web session's locale.
     *
     * @return A date formatted according to the active locale.
     */
    public String getDateString() {

        return DateTimeFormat.mediumDateTime().withLocale(WebUtil.getLocale()).print(shotTime());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int compareTo(final Media o) {

        return shotTime().compareTo(o.shotTime());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object o) {

        if (o == this)
            return true;
        if (!getClass().isInstance(o))
            return false;

        return Objects.equal(((Media) o).getName(), getName())
                && Objects.equal(((Media) o).getSource(), getSource());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {

        return Objects.hashCode(getName(), getSource());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {

        return String.format("{media: name=%s}", name);
    }

    @Override
    public String getLocalizedType() {

        return msgs.type();
    }

    @Override
    public String getLocalizedInstance() {

        return msgs.instance(name);
    }

    private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {

        // Default deserialization.
        stream.defaultReadObject();

        // Manually load a new Messages proxy.
        MessagesFactory.initialize(this, Messages.class);
    }

    /**
     * <h2>{@link Quality}<br> <sub>The media resource is available at different {@link Quality} levels.</sub></h2>
     *
     * <p> <i>Jan 6, 2010</i> </p>
     *
     * @author lhunath
     */
    public enum Quality {

        /**
         * The full quality of the original media file.
         */
        ORIGINAL("original", -1, -1, 1),

        /**
         * Media quality fit for displaying the media such that it fills the screen.
         */
        FULLSCREEN("fullscreen", 10000, 768, 0.9f),

        /**
         * Media quality fit for previewing the media at a size where it is easy to tell what it depicts.
         */
        PREVIEW("preview", 10000, 450, 0.8f),

        /**
         * Media quality fit for giving a hint on what the media is about.
         */
        THUMBNAIL("thumbnail", 1000, 100, 0.75f);

        private final String name;
        private final int maxWidth;
        private final int maxHeight;
        private final float compression;

        Quality(final String name, final int maxWidth, final int maxHeight, final float compression) {

            this.name = checkNotNull(name, "Given quality name must not be null.");
            this.maxWidth = maxWidth;
            this.maxHeight = maxHeight;
            this.compression = compression;
        }

        /**
         * @return The identifier used for this quality.
         */
        public String getName() {

            return name;
        }

        /**
         * @return The maximum width media at this quality should have, or <code>-1</code> if there should be no limit.
         */
        public int getMaxWidth() {

            return maxWidth;
        }

        /**
         * @return The maximum height media at this quality should have, or <code>-1</code> if there should be no limit.
         */
        public int getMaxHeight() {

            return maxHeight;
        }

        /**
         * @return The compression ratio media at this quality should use. A decimal number between <code>0</code> and <code>1</code>
         *         (inclusive) where <code>1</code> indicates maximum quality.
         */
        public float getCompression() {

            return compression;
        }

        /**
         * Find the {@link Quality} by the given name.
         *
         * @param qualityName The name of the quality (case insensitive) you're after.
         *
         * @return <code>null</code> if no quality exists for the given name.
         *
         * @see #getName()
         */
        public static Quality findQualityWithName(final String qualityName) {

            for (final Quality quality : Quality.values())
                if (quality.getName().equalsIgnoreCase(qualityName))
                    return quality;

            return null;
        }
    }

    interface Messages {

        /**
         * @return The name of this type.
         */
        String type();

        /**
         * @param name The name of the media.
         *
         * @return A description of a media.
         */
        String instance(String name);
    }
}