Java tutorial
/** * 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()); } }