src/net/fortuna/ical4j/model/TimeZoneRegistryImpl.java

Tue, 10 Feb 2015 18:12:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 18:12:00 +0100
changeset 0
fb9019fb1bf7
child 3
73bdfa70b04e
permissions
-rw-r--r--

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

     1 /**
     2  * Copyright (c) 2012, Ben Fortuna
     3  * All rights reserved.
     4  *
     5  * Redistribution and use in source and binary forms, with or without
     6  * modification, are permitted provided that the following conditions
     7  * are met:
     8  *
     9  *  o Redistributions of source code must retain the above copyright
    10  * notice, this list of conditions and the following disclaimer.
    11  *
    12  *  o Redistributions in binary form must reproduce the above copyright
    13  * notice, this list of conditions and the following disclaimer in the
    14  * documentation and/or other materials provided with the distribution.
    15  *
    16  *  o Neither the name of Ben Fortuna nor the names of any other contributors
    17  * may be used to endorse or promote products derived from this software
    18  * without specific prior written permission.
    19  *
    20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  */
    32 package net.fortuna.ical4j.model;
    34 import java.io.IOException;
    35 import java.net.URL;
    36 import java.util.Map;
    37 import java.util.Properties;
    38 import java.util.regex.Matcher;
    39 import java.util.regex.Pattern;
    41 import net.fortuna.ical4j.data.CalendarBuilder;
    42 import net.fortuna.ical4j.data.ParserException;
    43 import net.fortuna.ical4j.model.component.VTimeZone;
    44 import net.fortuna.ical4j.model.property.TzUrl;
    45 import net.fortuna.ical4j.util.CompatibilityHints;
    46 import net.fortuna.ical4j.util.Configurator;
    47 import net.fortuna.ical4j.util.ResourceLoader;
    49 import org.apache.commons.logging.Log;
    50 import org.apache.commons.logging.LogFactory;
    52 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
    54 /**
    55  * $Id$
    56  *
    57  * Created on 18/09/2005
    58  *
    59  * The default implementation of a <code>TimeZoneRegistry</code>. This implementation will search the classpath for
    60  * applicable VTimeZone definitions used to back the provided TimeZone instances.
    61  * @author Ben Fortuna
    62  */
    63 public class TimeZoneRegistryImpl implements TimeZoneRegistry {
    65     private static final String DEFAULT_RESOURCE_PREFIX = "zoneinfo/";
    67     private static final Pattern TZ_ID_SUFFIX = Pattern.compile("(?<=/)[^/]*/[^/]*$");
    69     private static final String UPDATE_ENABLED = "net.fortuna.ical4j.timezone.update.enabled";
    71     private static final Map DEFAULT_TIMEZONES = new ConcurrentHashMap();
    73     private static final Properties ALIASES = new Properties();
    74     static {
    75         try {
    76         	//ALIASES.load(ResourceLoader.getResourceAsStream("net/fortuna/ical4j/model/tz.alias"));
    77         	ALIASES.load(TimeZoneRegistryImpl.class.getResourceAsStream("tz.alias"));
    78              }
    79         catch (IOException ioe) {
    80             LogFactory.getLog(TimeZoneRegistryImpl.class).warn(
    81                     "Error loading timezone aliases: " + ioe.getMessage());
    82         }
    83     }
    85     private Map timezones;
    87     private String resourcePrefix;
    89     /**
    90      * Default constructor.
    91      */
    92     public TimeZoneRegistryImpl() {
    93         this(DEFAULT_RESOURCE_PREFIX);
    94     }
    96     /**
    97      * Creates a new instance using the specified resource prefix.
    98      * @param resourcePrefix a prefix prepended to classpath resource lookups for default timezones
    99      */
   100     public TimeZoneRegistryImpl(final String resourcePrefix) {
   101         this.resourcePrefix = resourcePrefix;
   102         timezones = new ConcurrentHashMap();
   103     }
   105     /**
   106      * {@inheritDoc}
   107      */
   108     public final void register(final TimeZone timezone) {
   109     	// for now we only apply updates to included definitions by default..
   110     	register(timezone, false);
   111     }
   113     /**
   114      * {@inheritDoc}
   115      */
   116     public final void register(final TimeZone timezone, boolean update) {
   117     	if (update) {
   118             // load any available updates for the timezone..
   119             timezones.put(timezone.getID(), new TimeZone(updateDefinition(timezone.getVTimeZone())));
   120     	}
   121     	else {
   122             timezones.put(timezone.getID(), timezone);
   123     	}
   124     }
   126     /**
   127      * {@inheritDoc}
   128      */
   129     public final void clear() {
   130         timezones.clear();
   131     }
   133     /**
   134      * {@inheritDoc}
   135      */
   136     public final TimeZone getTimeZone(final String id) {
   137         TimeZone timezone = (TimeZone) timezones.get(id);
   138         if (timezone == null) {
   139             timezone = (TimeZone) DEFAULT_TIMEZONES.get(id);
   140             if (timezone == null) {
   141                 // if timezone not found with identifier, try loading an alias..
   142                 final String alias = ALIASES.getProperty(id);
   143                 if (alias != null) {
   144                     return getTimeZone(alias);
   145                 }
   146                 else {
   147                     synchronized (DEFAULT_TIMEZONES) {
   148                     	// check again as it may be loaded now..
   149                     	timezone = (TimeZone) DEFAULT_TIMEZONES.get(id);
   150                     	if (timezone == null) {
   151                             try {
   152                                 final VTimeZone vTimeZone = loadVTimeZone(id);
   153                                 if (vTimeZone != null) {
   154                                     // XXX: temporary kludge..
   155                                     // ((TzId) vTimeZone.getProperties().getProperty(Property.TZID)).setValue(id);
   156                                     timezone = new TimeZone(vTimeZone);
   157                                     DEFAULT_TIMEZONES.put(timezone.getID(), timezone);
   158                                 }
   159                                 else if (CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING)) {
   160                                     // strip global part of id and match on default tz..
   161                                     Matcher matcher = TZ_ID_SUFFIX.matcher(id);
   162                                     if (matcher.find()) {
   163                                         return getTimeZone(matcher.group());
   164                                     }
   165                                 }
   166                             }
   167                             catch (Exception e) {
   168                                 Log log = LogFactory.getLog(TimeZoneRegistryImpl.class);
   169                                 log.warn("Error occurred loading VTimeZone", e);
   170                             }
   171                     	}
   172                     }
   173                 }
   174             }
   175         }
   176         return timezone;
   177     }
   179     /**
   180      * Loads an existing VTimeZone from the classpath corresponding to the specified Java timezone.
   181      */
   182     private VTimeZone loadVTimeZone(final String id) throws IOException, ParserException {
   183         //final URL resource = ResourceLoader.getResource(resourcePrefix + id + ".ics");
   184         final URL resource = TimeZoneRegistryImpl.class.getClassLoader().getResource(resourcePrefix + id + ".ics");
   185         if (resource != null) {
   186             final CalendarBuilder builder = new CalendarBuilder();
   187             final Calendar calendar = builder.build(resource.openStream());
   188             final VTimeZone vTimeZone = (VTimeZone) calendar.getComponent(Component.VTIMEZONE);
   189             // load any available updates for the timezone.. can be explicility disabled via configuration
   190             if (!"false".equals(Configurator.getProperty(UPDATE_ENABLED))) {
   191                 return updateDefinition(vTimeZone);
   192             }
   193             return vTimeZone;
   194         }
   195         return null;
   196     }
   198     /**
   199      * @param vTimeZone
   200      * @return
   201      */
   202     private VTimeZone updateDefinition(VTimeZone vTimeZone) {
   203         final TzUrl tzUrl = vTimeZone.getTimeZoneUrl();
   204         if (tzUrl != null) {
   205             try {
   206                 final CalendarBuilder builder = new CalendarBuilder();
   207                 final Calendar calendar = builder.build(tzUrl.getUri().toURL().openStream());
   208                 final VTimeZone updatedVTimeZone = (VTimeZone) calendar.getComponent(Component.VTIMEZONE);
   209                 if (updatedVTimeZone != null) {
   210                     return updatedVTimeZone;
   211                 }
   212             }
   213             catch (Exception e) {
   214                 Log log = LogFactory.getLog(TimeZoneRegistryImpl.class);
   215                 log.warn("Unable to retrieve updates for timezone: " + vTimeZone.getTimeZoneId().getValue(), e);
   216             }
   217         }
   218         return vTimeZone;
   219     }
   220 }

mercurial