hack/model/TimeZoneRegistryImpl.java

Fri, 13 Feb 2015 23:45:37 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 13 Feb 2015 23:45:37 +0100
branch
ICAL4J_EMBED_1
changeset 18
6dcaece8ec41
permissions
-rw-r--r--

Give up after a longwinded and unfruitful attempt to patch ical4j,
made difficult by the neverending graph of method calls leading up
to the NPE caused in getResource*() of the ResourceLoader class.

     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 android.util.Log;
    51 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
    53 /**
    54  * $Id$
    55  *
    56  * Created on 18/09/2005
    57  *
    58  * The default implementation of a <code>TimeZoneRegistry</code>. This implementation will search the classpath for
    59  * applicable VTimeZone definitions used to back the provided TimeZone instances.
    60  * @author Ben Fortuna
    61  */
    62 public class TimeZoneRegistryImpl implements TimeZoneRegistry {
    64     private static final String DEFAULT_RESOURCE_PREFIX = "zoneinfo/";
    66     private static final Pattern TZ_ID_SUFFIX = Pattern.compile("(?<=/)[^/]*/[^/]*$");
    68     private static final String UPDATE_ENABLED = "net.fortuna.ical4j.timezone.update.enabled";
    70     private static final Map DEFAULT_TIMEZONES = new ConcurrentHashMap();
    72     private static final Properties ALIASES = new Properties();
    73     static {
    74         try {
    75             ALIASES.load(ResourceLoader.getResourceAsStream("tz.alias"));
    76         }
    77         catch (IOException ioe) {
    78 			Log.w("MSvB-Hack", "Error loading timezone aliases: " + ioe.getMessage());
    79         }
    80         try {
    81         	ALIASES.load(ResourceLoader.getResourceAsStream("/tz.alias"));
    82         }
    83         catch (Exception e) {
    84 			Log.d("MSvB-Hack", "Error loading custom timezone aliases: " + e.getMessage());
    85         }
    86     }
    88     private Map timezones;
    90     private String resourcePrefix;
    92     /**
    93      * Default constructor.
    94      */
    95     public TimeZoneRegistryImpl() {
    96         this(DEFAULT_RESOURCE_PREFIX);
    97     }
    99     /**
   100      * Creates a new instance using the specified resource prefix.
   101      * @param resourcePrefix a prefix prepended to classpath resource lookups for default timezones
   102      */
   103     public TimeZoneRegistryImpl(final String resourcePrefix) {
   104         this.resourcePrefix = resourcePrefix;
   105         timezones = new ConcurrentHashMap();
   106     }
   108     /**
   109      * {@inheritDoc}
   110      */
   111     public final void register(final TimeZone timezone) {
   112     	// for now we only apply updates to included definitions by default..
   113     	register(timezone, false);
   114     }
   116     /**
   117      * {@inheritDoc}
   118      */
   119     public final void register(final TimeZone timezone, boolean update) {
   120     	if (update) {
   121             // load any available updates for the timezone..
   122             timezones.put(timezone.getID(), new TimeZone(updateDefinition(timezone.getVTimeZone())));
   123     	}
   124     	else {
   125             timezones.put(timezone.getID(), timezone);
   126     	}
   127     }
   129     /**
   130      * {@inheritDoc}
   131      */
   132     public final void clear() {
   133         timezones.clear();
   134     }
   136     /**
   137      * {@inheritDoc}
   138      */
   139     public final TimeZone getTimeZone(final String id) {
   140         TimeZone timezone = (TimeZone) timezones.get(id);
   141         if (timezone == null) {
   142             timezone = (TimeZone) DEFAULT_TIMEZONES.get(id);
   143             if (timezone == null) {
   144                 // if timezone not found with identifier, try loading an alias..
   145                 final String alias = ALIASES.getProperty(id);
   146                 if (alias != null) {
   147                     return getTimeZone(alias);
   148                 }
   149                 else {
   150                     synchronized (DEFAULT_TIMEZONES) {
   151                     	// check again as it may be loaded now..
   152                     	timezone = (TimeZone) DEFAULT_TIMEZONES.get(id);
   153                     	if (timezone == null) {
   154                             try {
   155                                 final VTimeZone vTimeZone = loadVTimeZone(id);
   156                                 if (vTimeZone != null) {
   157                                     // XXX: temporary kludge..
   158                                     // ((TzId) vTimeZone.getProperties().getProperty(Property.TZID)).setValue(id);
   159                                     timezone = new TimeZone(vTimeZone);
   160                                     DEFAULT_TIMEZONES.put(timezone.getID(), timezone);
   161                                 }
   162                                 else if (CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING)) {
   163                                     // strip global part of id and match on default tz..
   164                                     Matcher matcher = TZ_ID_SUFFIX.matcher(id);
   165                                     if (matcher.find()) {
   166                                         return getTimeZone(matcher.group());
   167                                     }
   168                                 }
   169                             }
   170                             catch (Exception e) {
   171                                 Log.w("MSvB-Hack", "Error occurred loading VTimeZone", e);
   172                             }
   173                     	}
   174                     }
   175                 }
   176             }
   177         }
   178         return timezone;
   179     }
   181     /**
   182      * Loads an existing VTimeZone from the classpath corresponding to the specified Java timezone.
   183      */
   184     private VTimeZone loadVTimeZone(final String id) throws IOException, ParserException {
   185         final URL resource = ResourceLoader.getResource(resourcePrefix + id + ".ics");
   186         if (resource != null) {
   187             final CalendarBuilder builder = new CalendarBuilder();
   188             final Calendar calendar = builder.build(resource.openStream());
   189             final VTimeZone vTimeZone = (VTimeZone) calendar.getComponent(Component.VTIMEZONE);
   190             // load any available updates for the timezone.. can be explicility disabled via configuration
   191             if (!"false".equals(Configurator.getProperty(UPDATE_ENABLED))) {
   192                 return updateDefinition(vTimeZone);
   193             }
   194             return vTimeZone;
   195         }
   196         return null;
   197     }
   199     /**
   200      * @param vTimeZone
   201      * @return
   202      */
   203     private VTimeZone updateDefinition(VTimeZone vTimeZone) {
   204         final TzUrl tzUrl = vTimeZone.getTimeZoneUrl();
   205         if (tzUrl != null) {
   206             try {
   207                 final CalendarBuilder builder = new CalendarBuilder();
   208                 final Calendar calendar = builder.build(tzUrl.getUri().toURL().openStream());
   209                 final VTimeZone updatedVTimeZone = (VTimeZone) calendar.getComponent(Component.VTIMEZONE);
   210                 if (updatedVTimeZone != null) {
   211                     return updatedVTimeZone;
   212                 }
   213             }
   214             catch (Exception e) {
   215                 Log.w("MSvB-Hack", "Unable to retrieve updates for timezone: " + vTimeZone.getTimeZoneId().getValue(), e);
   216             }
   217         }
   218         return vTimeZone;
   219     }
   220 }

mercurial