com.outerspacecat.icalendar.VCalendar.java Source code

Java tutorial

Introduction

Here is the source code for com.outerspacecat.icalendar.VCalendar.java

Source

/**
 * Copyright 2011 Caleb Richardson
 * 
 * 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.outerspacecat.icalendar;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayDeque;
import java.util.Deque;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMultimap;

/**
 * A representation of an iCalendar object defined by <a
 * href="http://tools.ietf.org/html/rfc5545">RFC 5545</a>. This class does not
 * enforce the amount of times a property or component is required or allowed to
 * appear.
 * 
 * @author Caleb Richardson
 */
@Immutable
@ThreadSafe
public final class VCalendar implements Serializable {
    private final static long serialVersionUID = 1L;

    private final ImmutableMultimap<String, Property> properties;
    private final ImmutableMultimap<String, Component> components;

    /**
     * Creates a new calendar.
     * 
     * @param properties the calendar properties. Must be non {@code null}, all
     *        elements must be non {@code null}, may be empty.
     * @param components the calendar components. Must be non {@code null}, all
     *        elements must be non {@code null}, may be empty.
     */
    public VCalendar(final Iterable<Property> properties, final Iterable<Component> components) {
        Preconditions.checkNotNull(properties, "properties required");
        Preconditions.checkNotNull(components, "components required");

        ImmutableMultimap.Builder<String, Property> propBuilder = new ImmutableMultimap.Builder<String, Property>();
        for (Property prop : properties) {
            Preconditions.checkNotNull(prop, "properties must each be non null");
            propBuilder.put(prop.getName().getName(), prop);
        }
        this.properties = propBuilder.build();

        ImmutableMultimap.Builder<String, Component> compBuilder = new ImmutableMultimap.Builder<String, Component>();
        for (Component comp : components) {
            Preconditions.checkNotNull(comp, "components must each be non null");
            compBuilder.put(comp.getName(), comp);
        }
        this.components = compBuilder.build();
    }

    /**
     * Returns the properties of this calendar.
     * 
     * @return the properties of this calendar. Never {@code null}, contains zero
     *         or more entries.
     */
    public ImmutableMultimap<String, Property> getProperties() {
        return properties;
    }

    /**
     * Returns the components of this calendar.
     * 
     * @return the components of this calendar. Never {@code null}, contains zero
     *         or more entries.
     */
    public ImmutableMultimap<String, Component> getComponents() {
        return components;
    }

    /**
     * Returns a single {@link Property} with the specified name, or {@code null}
     * if no such property exists. This method provides an easy way to ignore
     * extra properties. Which property is returned is non-deterministic, however
     * the same property will be returned each time this method is called.
     * 
     * @param name the name of the property to retrieve. Must be non {@code null}.
     * @return a single {@link Property} with the specified name, or {@code null}
     *         if no such property exists.
     */
    public Property getFirstProperty(final String name) {
        Preconditions.checkNotNull(name, "name required");

        ImmutableCollection<Property> props = getProperties().get(name.toUpperCase());
        return props.isEmpty() ? null : props.iterator().next();
    }

    /**
     * Returns a single {@link Property} with the specified name, or throws a
     * {@link CalendarParseException} if a property with the specified name does
     * not occur exactly once.
     * 
     * @param name the name of the property to retrieve. Must be non {@code null}.
     * @return a single {@link Property} with the specified name. Never
     *         {@code null}.
     * @throws CalendarParseException if a property with the specified name does
     *         not occur exactly once.
     */
    public Property getSingleProperty(final String name) throws CalendarParseException {
        Preconditions.checkNotNull(name, "name required");

        ImmutableCollection<Property> props = getProperties().get(name.toUpperCase());
        if (props.isEmpty())
            throw new CalendarParseException("no properties for name: " + name);
        if (props.size() > 1)
            throw new CalendarParseException("more than one property for name: " + name);
        return props.iterator().next();
    }

    /**
     * Converts this object to iCalendar and writes it to {@code sink}.
     * 
     * @param sink the character sink to write the generated iCalendar to. Must be
     *        non {@code null}.
     * @throws IOException if an error occurs while writing to {@code sink}
     */
    public void toICalendar(final Appendable sink) throws IOException {
        Preconditions.checkNotNull(sink, "sink required");

        sink.append("BEGIN:VCALENDAR\r\n");
        for (Property p : getProperties().values())
            sink.append(p.toICalendar()).append("\r\n");
        for (Component c : getComponents().values())
            c.toICalendar(sink);
        sink.append("END:VCALENDAR\r\n");
    }

    /**
     * A builder for creating instances of {@link VCalendar}.
     */
    final static class Builder {
        private final Deque<Property> properties = new ArrayDeque<Property>();
        private final Deque<Component> components = new ArrayDeque<Component>();

        /**
         * Adds a property to the calendar.
         * 
         * @param prop the property to add. Must be non {@code null}.
         * @return this builder. Never {@code null}.
         */
        public Builder addProperty(final Property prop) {
            Preconditions.checkNotNull(prop, "prop required");

            properties.add(prop);
            return this;
        }

        /**
         * Adds a component to the calendar.
         * 
         * @param comp the component to add. Must be non {@code null}.
         * @return this builder. Never {@code null}.
         */
        public Builder addComponent(final Component comp) {
            Preconditions.checkNotNull(comp, "comp required");

            components.add(comp);
            return this;
        }

        /**
         * Builds the calendar.
         * 
         * @return a new calendar. Never {@code null}.
         */
        public VCalendar build() {
            return new VCalendar(properties, components);
        }
    }
}