com.outerspacecat.icalendar.VTimeZone.java Source code

Java tutorial

Introduction

Here is the source code for com.outerspacecat.icalendar.VTimeZone.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 com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;

/**
 * A representation of an iCalendar VTIMEZONE component defined by <a
 * href="http://tools.ietf.org/html/rfc5545">RFC 5545</a>.
 * 
 * @author Caleb Richardson
 */
@Immutable
@ThreadSafe
public final class VTimeZone implements HasComponent, Serializable {
    private final static long serialVersionUID = 1L;

    public final static VTimeZone UTC = new VTimeZone(TypedProperty.wrap(new TextType("UTC")),
            ImmutableSet.of(new VTimeZoneObservance(VTimeZoneObservance.Type.STANDARD,
                    TypedProperty.wrap(LocalDateTime.of(1582, 10, 15, 0, 0, 0)),
                    TypedProperty.wrap(UtcOffsetType.ZERO), TypedProperty.wrap(UtcOffsetType.ZERO),
                    ImmutableSet.<RRule>of(), ImmutableSet.<RDate>of(), ImmutableSet.<Property>of())),
            ImmutableSet.<Property>of(), ImmutableSet.<Component>of());

    private final static ImmutableSet<String> RESTRICTED_PROPERTY_NAMES = ImmutableSet.of("TZID");

    private final static ImmutableSet<String> RESTRICTED_COMPONENT_NAMES = ImmutableSet.of("STANDARD", "DAYLIGHT");

    private final TypedProperty<TextType> id;
    private final ImmutableSet<VTimeZoneObservance> observances;
    private final ImmutableMultimap<String, Property> extraProperties;
    private final ImmutableMultimap<String, Component> extraComponents;

    /**
     * Creates a new time zone.
     * 
     * @param id the time zone id. Must be non {@code null}.
     * @param observances the time zone observances. Must be non {@code null}, all
     *        elements must be non {@code null}. Must contain at least one
     *        element.
     * @param extraProperties the extra properties of the time zone. Must be non
     *        {@code null}, all elements must be non {@code null}, may be empty.
     * @param extraComponents the extra components of the time zone. Must be non
     *        {@code null}, all elements must be non {@code null}, may be empty.
     */
    public VTimeZone(final TypedProperty<TextType> id, final Iterable<VTimeZoneObservance> observances,
            final Iterable<Property> extraProperties, final Iterable<Component> extraComponents) {
        Preconditions.checkNotNull(id, "id required");
        Preconditions.checkNotNull(observances, "observances required");
        Preconditions.checkArgument(observances.iterator().hasNext(), "one or more observances required");
        for (VTimeZoneObservance observance : observances)
            Preconditions.checkNotNull(observance, "each observance must be non null");
        Preconditions.checkNotNull(extraProperties, "extraProperties required");
        for (Property prop : extraProperties)
            Preconditions.checkNotNull(prop, "each extra property must be non null");
        Preconditions.checkNotNull(extraComponents, "extraComponents required");
        for (Component comp : extraComponents)
            Preconditions.checkNotNull(comp, "each extra component must be non null");

        this.id = id;

        this.observances = ImmutableSet.copyOf(observances);

        ImmutableMultimap.Builder<String, Property> extraPropertiesBuilder = ImmutableMultimap.builder();
        for (Property prop : extraProperties)
            extraPropertiesBuilder.put(prop.getName().getName(), prop);
        this.extraProperties = extraPropertiesBuilder.build();

        ImmutableMultimap.Builder<String, Component> extraComponentsBuilder = ImmutableMultimap.builder();
        for (Component comp : extraComponents)
            extraComponentsBuilder.put(comp.getName(), comp);
        this.extraComponents = extraComponentsBuilder.build();
    }

    /**
     * Parses a time zone component.
     * 
     * @param comp the component to parse. Must be non {@code null}.
     * @return a time zone. Never {@code null}.
     * @throws CalendarParseException if {@code comp} does not represent a valid
     *         time zone
     */
    public static VTimeZone parse(final Component comp) throws CalendarParseException {
        Preconditions.checkNotNull(comp, "comp required");
        Preconditions.checkArgument(comp.getName().equals("VTIMEZONE"),
                "component name must be VTIMEZONE, saw: " + comp.getName());

        Property prop = comp.getSingleProperty("TZID");
        TypedProperty<TextType> id = new TypedProperty<>(prop.asText(), prop.getParameters().values());

        ImmutableSet.Builder<VTimeZoneObservance> componentsBuilder = ImmutableSet.builder();

        for (Component standard : comp.getComponents().get("STANDARD"))
            componentsBuilder.add(VTimeZoneObservance.parse(standard));

        for (Component daylight : comp.getComponents().get("DAYLIGHT"))
            componentsBuilder.add(VTimeZoneObservance.parse(daylight));

        return new VTimeZone(id, componentsBuilder.build(),
                comp.getPropertiesExcept(RESTRICTED_PROPERTY_NAMES).values(),
                comp.getComponentsExcept(RESTRICTED_COMPONENT_NAMES).values());
    }

    /**
     * Returns the id of this time zone.
     * 
     * @return the id of this time zone. Never {@code null}.
     */
    public TypedProperty<TextType> getId() {
        return id;
    }

    /**
     * Returns the observances of this time zone.
     * 
     * @return the observances of this time zone. Never {@code null}, contains one
     *         or more elements.
     */
    private ImmutableSet<VTimeZoneObservance> getObservances() {
        return observances;
    }

    /**
     * Returns the extra properties of this time zone.
     * 
     * @return the extra parameters of this time zone. Never {@code null}, may be
     *         empty.
     */
    public ImmutableMultimap<String, Property> getExtraProperties() {
        return extraProperties;
    }

    /**
     * Returns the extra components of this time zone.
     * 
     * @return the extra components of this time zone. Never {@code null}, may be
     *         empty.
     */
    public ImmutableMultimap<String, Component> getExtraComponents() {
        return extraComponents;
    }

    @Override
    public Component toComponent(final HasTimeZones timeZones) {
        Preconditions.checkNotNull(timeZones, "timeZones required");
        Component.Builder builder = new Component.Builder();

        builder.setName("VTIMEZONE");
        builder.addProperty(
                new Property(new PropertyName("TZID"), id.getValue().getValue(), id.getExtraParameters().values()));
        for (VTimeZoneObservance observance : getObservances())
            builder.addComponent(observance.toComponent(timeZones));

        for (Property prop : getExtraProperties().values())
            builder.addProperty(prop);

        for (Component comp : getExtraComponents().values())
            builder.addComponent(comp);

        return builder.build();
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getId(), getObservances());
    }

    @Override
    public boolean equals(final Object obj) {
        return obj instanceof VTimeZone && Objects.equal(getId(), ((VTimeZone) obj).getId())
                && Objects.equal(getObservances(), ((VTimeZone) obj).getObservances());
    }

    /**
     * Returns a time zone for the specified offset.
     * 
     * @param offset the offset to use. Must be non {@code null}.
     * @return a time zone for the specified offset. Never {@code null}.
     */
    public static VTimeZone forOffset(final UtcOffsetType offset) {
        Preconditions.checkNotNull(offset, "offset required");

        return new VTimeZone(TypedProperty.wrap(new TextType(offset.toString())),
                ImmutableSet.of(new VTimeZoneObservance(VTimeZoneObservance.Type.STANDARD,
                        TypedProperty.wrap(LocalDateTime.of(1582, 10, 15, 0, 0, 0)), TypedProperty.wrap(offset),
                        TypedProperty.wrap(offset), ImmutableSet.<RRule>of(), ImmutableSet.<RDate>of(),
                        ImmutableSet.<Property>of())),
                ImmutableSet.<Property>of(), ImmutableSet.<Component>of());
    }
}