[Bedework-commit] timezones r30 - in trunk: . .settings lib olson olson/src olson/src/org olson/src/org/bedework olson/src/org/bedework/timezones olson/src/org/bedework/timezones/olson resources tzsvr/src/org/bedework/timezones/server tzsvr/war/WEB-INF/classes tzutil/src/org/bedework/timezones/tzutil

svnadmin at bedework.org svnadmin at bedework.org
Thu Jul 24 15:43:30 EDT 2008


Author: douglm
Date: 2008-07-24 15:43:24 -0400 (Thu, 24 Jul 2008)
New Revision: 30

Added:
   trunk/lib/backport-util-concurrent-3.0.jar
   trunk/lib/ehcache-1.5.0.jar
   trunk/lib/jsr107cache-1.0.jar
   trunk/lib/rpiutil-3.5.jar
   trunk/olson/
   trunk/olson/src/
   trunk/olson/src/org/
   trunk/olson/src/org/bedework/
   trunk/olson/src/org/bedework/timezones/
   trunk/olson/src/org/bedework/timezones/olson/
   trunk/olson/src/org/bedework/timezones/olson/Parser.java
   trunk/olson/src/org/bedework/timezones/olson/ParserSource.java
   trunk/olson/src/org/bedework/timezones/olson/Process.java
   trunk/olson/src/org/bedework/timezones/olson/RuleSet.java
   trunk/olson/src/org/bedework/timezones/olson/TzData.java
   trunk/olson/src/org/bedework/timezones/olson/Zone.java
   trunk/resources/
   trunk/resources/log4j.xml
   trunk/resources/tzregistry.xml
   trunk/tzsvr/war/WEB-INF/classes/ehcache.xml
Removed:
   trunk/lib/rpiutil-3.2.jar
Modified:
   trunk/.classpath
   trunk/.settings/org.eclipse.jdt.core.prefs
   trunk/tzsvr/src/org/bedework/timezones/server/GetMethod.java
   trunk/tzsvr/src/org/bedework/timezones/server/TzServer.java
   trunk/tzsvr/src/org/bedework/timezones/server/TzServerUtil.java
   trunk/tzsvr/war/WEB-INF/classes/servlet.properties
   trunk/tzutil/src/org/bedework/timezones/tzutil/Reader.java
   trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneChange.java
   trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneDef.java
   trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneInfo.java
   trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneProvider.java
   trunk/tzutil/src/org/bedework/timezones/tzutil/TzUtil.java
   trunk/tzutil/src/org/bedework/timezones/tzutil/VtoXml.java
   trunk/tzutil/src/org/bedework/timezones/tzutil/XmlToV.java
Log:
More work on timezone database population tool and server

Modified: trunk/.classpath
===================================================================
--- trunk/.classpath	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/.classpath	2008-07-24 19:43:24 UTC (rev 30)
@@ -1,15 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="tzsvr/src"/>
+	<classpathentry kind="src" path="olson/src"/>
 	<classpathentry kind="src" path="tzutil/src"/>
 	<classpathentry kind="lib" path="lib/derby.jar"/>
 	<classpathentry kind="lib" path="lib/geronimo-stax-api_1.0_spec-1.0.jar"/>
-	<classpathentry kind="lib" path="lib/ical4j-head.jar"/>
+	<classpathentry kind="lib" path="lib/ical4j-head.jar" sourcepath="/iCal4j/source"/>
 	<classpathentry kind="lib" path="lib/log4j-1.2.8.jar"/>
-	<classpathentry kind="lib" path="lib/rpiutil-3.2.jar"/>
 	<classpathentry kind="lib" path="lib/servletapi-2.4.jar"/>
 	<classpathentry kind="lib" path="lib/wstx-asl-3.9.0.jar"/>
+	<classpathentry kind="lib" path="lib/commons-httpclient-3.0.jar"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry kind="lib" path="lib/commons-httpclient-3.0.jar"/>
+	<classpathentry kind="lib" path="lib/ehcache-1.5.0.jar" sourcepath="/home/douglm/drop2/db/ehcache/ehcache-1.5.0/ehcache-1.5.0-sources"/>
+	<classpathentry kind="lib" path="lib/rpiutil-3.5.jar"/>
 	<classpathentry kind="output" path="bin/timezones"/>
 </classpath>

Modified: trunk/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- trunk/.settings/org.eclipse.jdt.core.prefs	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/.settings/org.eclipse.jdt.core.prefs	2008-07-24 19:43:24 UTC (rev 30)
@@ -1,4 +1,4 @@
-#Tue Apr 15 15:22:42 EDT 2008
+#Sun Jun 29 00:40:52 EDT 2008
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
 org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
@@ -111,7 +111,7 @@
 org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
 org.eclipse.jdt.core.formatter.comment.line_length=80
 org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation=8
 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
 org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true

Added: trunk/lib/backport-util-concurrent-3.0.jar
===================================================================
(Binary files differ)


Property changes on: trunk/lib/backport-util-concurrent-3.0.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/lib/ehcache-1.5.0.jar
===================================================================
(Binary files differ)


Property changes on: trunk/lib/ehcache-1.5.0.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/lib/jsr107cache-1.0.jar
===================================================================
(Binary files differ)


Property changes on: trunk/lib/jsr107cache-1.0.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Deleted: trunk/lib/rpiutil-3.2.jar
===================================================================
(Binary files differ)

Added: trunk/lib/rpiutil-3.5.jar
===================================================================
(Binary files differ)


Property changes on: trunk/lib/rpiutil-3.5.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/olson/src/org/bedework/timezones/olson/Parser.java
===================================================================
--- trunk/olson/src/org/bedework/timezones/olson/Parser.java	                        (rev 0)
+++ trunk/olson/src/org/bedework/timezones/olson/Parser.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,50 @@
+package org.bedework.timezones.olson;
+
+public class Parser {
+  private ParserSource psrc;
+
+  private boolean debug;
+  
+  public TzData parseFile(String fileName,
+                          boolean debug) throws Throwable {
+    this.debug = debug;
+    psrc = new ParserSource(fileName, debug);
+
+    TzData tzd = new TzData();
+
+    while (psrc.nextTokens()) {
+      if (psrc.tokenEquals("Zone", 0)) {
+        parseZone();
+      } else {
+        error("Unknown entry type " + psrc.getCurLine());
+      }
+    }
+    return tzd;
+  }
+  
+  /** 
+   *      
+   * @return Zone
+   */
+  public Zone parseZone() {
+    if (debug) {
+      trace("parseZone entry");
+    }
+    
+    Zone z = new Zone(psrc);
+    
+    if (!z.parse()) {
+      return null;
+    }
+    
+    return z;
+  }
+  
+  private void trace(String val) {
+    System.out.println("DEBUG: " + val);
+  }
+  
+  private void error(String val) {
+    System.err.println(val);
+  }
+}

Added: trunk/olson/src/org/bedework/timezones/olson/ParserSource.java
===================================================================
--- trunk/olson/src/org/bedework/timezones/olson/ParserSource.java	                        (rev 0)
+++ trunk/olson/src/org/bedework/timezones/olson/ParserSource.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,241 @@
+package org.bedework.timezones.olson;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.io.Reader;
+
+import org.bedework.timezones.olson.TzData.TimeData;
+
+/** Source for parsing datafiles
+ * 
+ * @author Mike Douglass
+ */
+public class ParserSource {
+  private LineNumberReader lnr;
+  private boolean atEof;
+  private String curLine;
+  
+  private String[] curTokens;
+
+  private boolean debug;
+  
+  public ParserSource(String fileName,
+                      boolean debug) throws Throwable {
+    this.debug = debug;
+    Reader rdr = new FileReader(new File(fileName));
+
+    lnr = new LineNumberReader(rdr);
+  }
+  
+  public boolean atEof() {
+    return atEof;
+  }
+  
+  public String getCurLine() {
+    return curLine;
+  }
+  
+  public String getToken(int pos) {
+    if ((curTokens == null) || (curTokens.length <= pos)) {
+      return null;
+    }
+    
+    return curTokens[pos];
+  }
+  
+  public boolean tokenEquals(String val, int pos) {
+    if ((curTokens == null) || (curTokens.length <= pos)) {
+      return false;
+    }
+    
+    return val.equals(curTokens[pos]);
+  }
+  
+  /** The indicated token should represent a time
+   * 
+   * @param pos
+   * @return TimeData seconds
+   */
+  public TimeData tokenTime(int pos) {
+    if ((curTokens == null) || (curTokens.length <= pos)) {
+      return null;
+    }
+    
+    return getTime(curTokens[pos]);
+  }
+  
+  /** Return a number or null
+   * 
+   * @param pos
+   * @return Integer or null if not a number
+   */
+  public Integer number(int pos) {
+    if ((curTokens == null) || (curTokens.length <= pos)) {
+      return null;
+    }
+    
+    try {
+      Integer res = Integer.valueOf(curTokens[pos]);
+    
+      return res;
+    } catch (NumberFormatException nfe) {
+      return null;
+    }
+  }
+  
+  private static class Token {
+    String val;
+    int pos;
+    
+    Token(String val) {
+      this.val = val;
+      this.pos = 0;
+    }
+    
+    boolean ifMatch(String val) {
+      if (atEnd()) {
+        return false;
+      }
+      
+      int len = val.length();
+      if (!val.regionMatches(pos, val, 0, len)) {
+        return false;
+      }
+      
+      pos += len;
+      return true;
+    }
+    
+    int number2() {
+      int res = Integer.valueOf(val.substring(pos, 2));
+      
+      pos += 2;
+      
+      return res;
+    }
+    
+    boolean atEnd() {
+      if (pos >= val.length()) {
+        return true;
+      }
+      
+      return false;
+    }
+  }
+  
+  /** Has form:
+   * <pre>
+   *   [-]hours[:minutes[:seconds]][w|s|g|u|z]
+   * </pre>
+   * Final code signifies wall (the default), standard, or UTC
+   * 
+   * @param val
+   * @return int number of seconds
+   */
+  private TimeData getTime(String val) {
+    TimeData td = new TimeData();
+    
+    Token tk = new Token(val);
+    
+    boolean neg = tk.ifMatch("-");
+      
+    td.seconds = tk.number2() * 60 * 60;
+    
+    if (tk.ifMatch(":")) {
+      td.seconds += (tk.number2() * 60);
+      if (tk.ifMatch(":")) {
+        td.seconds += tk.number2();
+      }
+    }
+    
+    if (neg) {
+      td.seconds = -td.seconds;
+    }
+    
+    if (tk.atEnd()) {
+      td.typeCode = TimeData.timeWall;
+    } else if (tk.ifMatch("w")) {
+      td.typeCode = TimeData.timeWall;
+    } else if (tk.ifMatch("s")) {
+      td.typeCode = TimeData.timeStandard;
+    } else if (tk.ifMatch("u")) {
+      td.typeCode = TimeData.timeUtc;
+    } else if (tk.ifMatch("z")) {
+      td.typeCode = TimeData.timeUtc;
+    } else if (tk.ifMatch("g")) {
+      td.typeCode = TimeData.timeUtc;
+    } else {
+      error("Bad time " + curLine);
+    }
+    
+    return td;
+  }
+  
+  /** Break the current line into an array of tokens.
+   * Return null for no tokens.
+   * 
+   * @return String[] tokens.
+   */
+  private String[] tokenize(String val) {
+    if (val == null) {
+      return null;
+    }
+    
+    if (val.startsWith("#") || (val.length() == 0)) {
+      return null;
+    }
+  
+    String[] res = val.split("\\s");
+    if ((res == null) || (res.length == 0)) {
+      return null;
+    }
+  
+    for (int i = 0; i < res.length; i++) {
+      if (res[i].startsWith("#")) {
+        // Comment from now on
+        if (i == 0) {
+          return null;
+        }
+        
+        String[] subRes = new String[i];
+        System.arraycopy(res, 0, subRes, 0 , i);
+
+        return subRes;
+      }
+    }
+
+    return res;
+  }
+  
+  public void trace(String val) {
+    System.out.println("DEBUG: " + val);
+  }
+  
+  public void error(String val) {
+    System.err.println(val);
+  }
+  
+  /* null for eof */
+  public boolean nextTokens() throws Throwable {
+    if (atEof) {
+      return false;
+    }
+    
+    for (;;) {
+      curLine = lnr.readLine();
+      
+      if (curLine == null) {
+        // EOF so they say
+        atEof = true;
+        return false;
+      }
+      
+      curTokens = tokenize(curLine);
+      
+      if (curTokens != null) {
+        return true;
+      }
+    }
+  }
+}

Added: trunk/olson/src/org/bedework/timezones/olson/Process.java
===================================================================
--- trunk/olson/src/org/bedework/timezones/olson/Process.java	                        (rev 0)
+++ trunk/olson/src/org/bedework/timezones/olson/Process.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,23 @@
+package org.bedework.timezones.olson;
+
+/** Process the current Olson data to produce an internal form suitable for a 
+ * timezone servie
+ * 
+ * @author Mike Douglass
+ */
+public class Process {
+
+  /**
+   * @param args
+   */
+  public static void main(String[] args) {
+    Parser p = new Parser();
+    
+    try {
+      TzData td = p.parseFile(args[0], true); 
+    } catch (Throwable t) {
+      t.printStackTrace();
+    }
+  }
+
+}

Added: trunk/olson/src/org/bedework/timezones/olson/RuleSet.java
===================================================================
--- trunk/olson/src/org/bedework/timezones/olson/RuleSet.java	                        (rev 0)
+++ trunk/olson/src/org/bedework/timezones/olson/RuleSet.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,5 @@
+package org.bedework.timezones.olson;
+
+public class RuleSet {
+
+}

Added: trunk/olson/src/org/bedework/timezones/olson/TzData.java
===================================================================
--- trunk/olson/src/org/bedework/timezones/olson/TzData.java	                        (rev 0)
+++ trunk/olson/src/org/bedework/timezones/olson/TzData.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,13 @@
+package org.bedework.timezones.olson;
+
+public class TzData {
+  public static class TimeData {
+    public final static int timeWall = 0;
+    public final static int timeStandard = 1;
+    public final static int timeUtc = 2;
+    
+    public int seconds;
+    public int typeCode;
+  }
+  
+}

Added: trunk/olson/src/org/bedework/timezones/olson/Zone.java
===================================================================
--- trunk/olson/src/org/bedework/timezones/olson/Zone.java	                        (rev 0)
+++ trunk/olson/src/org/bedework/timezones/olson/Zone.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,119 @@
+package org.bedework.timezones.olson;
+
+import java.io.Serializable;
+
+import org.bedework.timezones.olson.TzData.TimeData;
+import org.bedework.timezones.olson.Zone.ZoneInfo.Until;
+
+public class Zone implements Serializable {
+  private ParserSource psrc;
+
+  public String name;
+
+  public static class ZoneInfo implements Serializable {
+    public static class Until implements Serializable {
+      int year;
+      int month;
+    }
+
+    public int offsetSeconds;
+
+    public String rulesetName;
+    public RuleSet rules;
+    public Integer seconds;
+
+    public String format;
+
+    /** null for no until part */
+    public Until until;
+  }
+
+  public Zone(ParserSource psrc) {
+    this.psrc = psrc;
+  }
+
+  /** The Zone starts with a line which has the keyword "Zone" at column 0 and
+   * continues over a number of lines until there is no UNTIL field.
+# Zone       NAME           GMTOFF     RULES    FORMAT      [UNTIL]
+Zone    America/Los_Angeles -7:52:58   -        LMT         1883 Nov 18 12:07:02
+                            -8:00      US       P%sT        1946
+                            -8:00      CA       P%sT        1967
+                            -8:00      US       P%sT
+
+   * @return boolean true for parsed OK.
+   */
+  public boolean parse() {
+    name = psrc.getToken(1);
+
+    int tnum = 2;
+    ZoneInfo zi;
+
+    do {
+      zi = new ZoneInfo();
+
+      TimeData secs = psrc.tokenTime(tnum);
+      zi.offsetSeconds = secs.seconds;
+
+      tnum++; // On to rules
+
+      zi.rulesetName = psrc.getToken(tnum);
+      if ("-".equals(zi.rulesetName)) {
+        zi.rulesetName = null;
+      } else {
+        zi.seconds = psrc.number(tnum);
+        if (zi.seconds != null) {
+          zi.rulesetName = null;
+        }
+      }
+
+      tnum++;   // On to format
+
+      zi.format = psrc.getToken(tnum);
+
+      tnum++;   // On to until part
+
+      if (psrc.getToken(tnum) != null) {
+        // Expecting an Until
+
+        zi.until = getUntil(tnum);
+      }
+    } while (zi.until != null);
+
+    return false;
+  }
+
+  private Until getUntil(int tnum) {
+    if (psrc.getToken(tnum) == null) {
+      return null;
+    }
+
+    Until until = new Until();
+
+    int fldNum = 0;
+    Integer fval;
+
+    while (psrc.getToken(tnum) != null) {
+      switch (fldNum) {
+      case 0:
+        fval = psrc.number(tnum);
+        if (fval == null) {
+          error("Bad year");
+          return until;
+        }
+
+        until.year = fval;
+        break;
+
+      case 1:
+        break;
+
+      }
+    }
+
+    return until;
+  }
+
+  private void error(String msg) {
+    System.err.println(msg + " at " + psrc.getCurLine());
+  }
+}

Added: trunk/resources/log4j.xml
===================================================================
--- trunk/resources/log4j.xml	                        (rev 0)
+++ trunk/resources/log4j.xml	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<!-- ===================================================================== -->
+<!--                                                                       -->
+<!--  Log4j Configuration                                                  -->
+<!--                                                                       -->
+<!-- ===================================================================== -->
+
+<!-- $Id: log4j.xml,v 1.5 2005/01/18 02:55:05 rpical Exp $ -->
+
+<!--
+   | For more configuration infromation and examples see the Jakarta Log4j
+   | website: http://jakarta.apache.org/log4j
+ -->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
+                     debug="false">
+
+   <!-- ================================= -->
+   <!-- Preserve messages in a local file -->
+   <!-- ================================= -->
+
+   <!-- A time/date based rolling appender -->
+   <appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
+      <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+      <param name="File" value="./server.log"/>
+      <param name="Append" value="true"/>
+
+      <!-- Rollover at midnight each day -->
+      <param name="DatePattern" value="'.'yyyy-MM-dd"/>
+
+      <!-- Rollover at the top of each hour
+      <param name="DatePattern" value="'.'yyyy-MM-dd-HH"/>
+      -->
+
+      <layout class="org.apache.log4j.PatternLayout">
+         <!-- The default pattern: Date Priority [Category] Message\n -->
+         <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
+
+         <!-- The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
+         <param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
+          -->
+      </layout>
+   </appender>
+
+   <!-- A size based file rolling appender
+   <appender name="FILE" class="org.jboss.logging.appender.RollingFileAppender">
+     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
+     <param name="File" value="${jboss.server.home.dir}/log/server.log"/>
+     <param name="Append" value="false"/>
+     <param name="MaxFileSize" value="500KB"/>
+     <param name="MaxBackupIndex" value="1"/>
+
+     <layout class="org.apache.log4j.PatternLayout">
+       <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
+     </layout>
+   </appender>
+   -->
+
+   <!-- ============================== -->
+   <!-- Append messages to the console -->
+   <!-- Set Threshold to INFO/DEBUG -->
+   <!-- ============================== -->
+
+   <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+      <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+      <param name="Target" value="System.out"/>
+      <param name="Threshold" value="DEBUG"/>
+
+      <layout class="org.apache.log4j.PatternLayout">
+         <!-- The default pattern: Date Priority [Category] Message\n -->
+         <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+      </layout>
+   </appender>
+
+   <appender name="JSR77" class="org.apache.log4j.FileAppender">
+      <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+      <param name="Append" value="false"/>
+      <param name="File" value="${tomcat.home}/logs/jsr77.log"/>
+      <layout class="org.apache.log4j.PatternLayout">
+         <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+      </layout>
+   </appender>
+
+   <!-- ====================== -->
+   <!-- More Appender examples -->
+   <!-- ====================== -->
+
+   <!-- Buffer events and log them asynchronously
+   <appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
+     <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+     <appender-ref ref="FILE"/>
+     <appender-ref ref="CONSOLE"/>
+     <appender-ref ref="SMTP"/>
+   </appender>
+   -->
+
+   <!-- EMail events to an administrator
+   <appender name="SMTP" class="org.apache.log4j.net.SMTPAppender">
+     <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+     <param name="Threshold" value="ERROR"/>
+     <param name="To" value="admin at myhost.domain.com"/>
+     <param name="From" value="nobody at myhost.domain.com"/>
+     <param name="Subject" value="JBoss Sever Errors"/>
+     <param name="SMTPHost" value="localhost"/>
+     <param name="BufferSize" value="10"/>
+     <layout class="org.apache.log4j.PatternLayout">
+       <param name="ConversionPattern" value="[%d{ABSOLUTE},%c{1}] %m%n"/>
+     </layout>
+   </appender>
+   -->
+
+   <!-- Syslog events
+   <appender name="SYSLOG" class="org.apache.log4j.net.SyslogAppender">
+     <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+     <param name="Facility" value="LOCAL7"/>
+     <param name="FacilityPrinting" value="true"/>
+     <param name="SyslogHost" value="localhost"/>
+   </appender>
+   -->
+
+   <!-- Log events to JMS (requires a topic to be created)
+   <appender name="JMS" class="org.apache.log4j.net.JMSAppender">
+     <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+     <param name="Threshold" value="ERROR"/>
+     <param name="TopicConnectionFactoryBindingName" value="java:/ConnectionFactory"/>
+     <param name="TopicBindingName" value="topic/MyErrorsTopic"/>
+   </appender>
+   -->
+
+   <!-- Log events through SNMP
+   <appender name="TRAP_LOG" class="org.apache.log4j.ext.SNMPTrapAppender">
+     <errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler"/>
+     <param name="ImplementationClassName" value="org.apache.log4j.ext.JoeSNMPTrapSender"/>
+     <param name="ManagementHost" value="127.0.0.1"/>
+     <param name="ManagementHostTrapListenPort" value="162"/>
+     <param name="EnterpriseOID" value="1.3.6.1.4.1.24.0"/>
+     <param name="LocalIPAddress" value="127.0.0.1"/>
+     <param name="LocalTrapSendPort" value="161"/>
+     <param name="GenericTrapType" value="6"/>
+     <param name="SpecificTrapType" value="12345678"/>
+     <param name="CommunityString" value="public"/>
+     <param name="ForwardStackTraceWithTrap" value="true"/>
+     <param name="Threshold" value="DEBUG"/>
+     <param name="ApplicationTrapOID" value="1.3.6.1.4.1.24.12.10.22.64"/>
+     <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%d,%p,[%t],[%c],%m%n"/>
+     </layout>
+   </appender>
+   -->
+
+  <appender name="CHAINSAW_CLIENT" class="org.apache.log4j.net.SocketAppender">
+      <param name="RemoteHost" value="localhost"/>
+      <param name="Port" value="4445"/>
+      <param name="LocationInfo" value="true"/>
+  </appender>
+
+   <!-- ================ -->
+   <!-- Limit categories -->
+   <!-- ================ -->
+
+   <!-- Limit the org.apache stuff -->
+   <!--
+   <category name="org.apache.commons">
+      <priority value="INFO"/>
+   </category>
+
+   <category name="org.apache.catalina.startup.TldConfig">
+      <priority value="INFO"/>
+   </category>
+
+   <category name="org.apache.jasper">
+      <priority value="INFO"/>
+   </category>
+
+   <category name="org.apache.struts">
+      <priority value="INFO"/>
+   </category>
+   -->
+   <category name="org.apache">
+      <priority value="INFO"/>
+   </category>
+
+   <!--
+   <category name="org.apache.commons.digester">
+      <priority value="DEBUG"/>
+   </category>
+   -->
+
+   <!--
+   <category name="org.apache.commons.beanutils">
+      <priority value="TRACE"/>
+   </category>
+   -->
+
+   <!-- ical4j is noisy -->
+   <category name="net.fortuna.ical4j">
+      <priority value="INFO"/>
+   </category>
+
+   <!-- caching is noisy too -->
+   <category name="net.sf.ehcache">
+      <priority value="INFO"/>
+   </category>
+
+   <!-- hibernate is noisy too -->
+   <category name="org.hibernate">
+      <priority value="INFO"/>
+   </category>
+
+   <!-- Set rpi categories -->
+<!--
+   <category name="edu.rpi">
+     <priority value="DEBUG"/>
+   </category>
+ -->
+
+   <category name="edu.rpi.cmt.access.Acl">
+     <priority value="INFO"/>
+   </category>
+
+   <category name="org.bedework.calcore.AccessUtil">
+     <priority value="INFO"/>
+   </category>
+
+   <!--
+      | An example of enabling the custom TRACE level priority that is used
+      | by the JBoss internals to diagnose low level details. This example
+      | turns on TRACE level msgs for the org.jboss.ejb.plugins package and its
+      | subpackages. This will produce A LOT of logging output.
+   <category name="org.jboss.system">
+     <priority value="TRACE" class="org.jboss.logging.XLevel"/>
+   </category>
+   <category name="org.jboss.ejb.plugins">
+     <priority value="TRACE" class="org.jboss.logging.XLevel"/>
+   </category>
+   -->
+
+   <!-- ======================= -->
+   <!-- Setup the Root category -->
+   <!-- ======================= -->
+
+   <root>
+      <priority value ="TRACE" />
+      <appender-ref ref="FILE"/>
+      <appender-ref ref="CONSOLE"/>
+   </root>
+</log4j:configuration>

Added: trunk/resources/tzregistry.xml
===================================================================
--- trunk/resources/tzregistry.xml	                        (rev 0)
+++ trunk/resources/tzregistry.xml	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+
+<timezone-registry>
+  <provider>
+    <prefix>/EXAMPLE</prefix>
+    <url>http://localhost:8080/tzsvr</url>
+    <contact>http://localhost:9090/carddav/orgs/Example</contact>
+  </provider>
+  <!--
+  <provider>
+    <prefix>/MICROSOFT</prefix>
+    <url>http://localhost:9090/mstzs</url>
+    <contact>http://localhost:9090/carddav/orgs/MS</contact>
+  </provider>
+  <provider>
+    <prefix>/APPLE</prefix>
+    <url>http://localhost:9090/appletzs</url>
+    <contact>http://localhost:9090/carddav/orgs/Apple</contact>
+  </provider>
+   -->
+</timezone-registry>

Modified: trunk/tzsvr/src/org/bedework/timezones/server/GetMethod.java
===================================================================
--- trunk/tzsvr/src/org/bedework/timezones/server/GetMethod.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzsvr/src/org/bedework/timezones/server/GetMethod.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -63,13 +63,8 @@
     String[] tzids = req.getParameterValues("tzid");
     String provider = req.getParameter("provider");
 
-    if (provider != null) {
-      // XXX We should see if this is one of our prefixes. If not we should call
-      // a server which does support that prefix - probably based on registry values.
-    }
+    TzUtil util = new TzUtil(props.getProperty(TzServerUtil.pnameDbName), debug);
 
-    TzUtil util = new TzUtil(debug);
-
     doTzids(resp, tzids, format, provider, util);
   }
 
@@ -78,8 +73,10 @@
                        TzUtil util) throws ServletException {
     Collection<TimezoneDef> tzdefs = new ArrayList<TimezoneDef>();
 
+    boolean fetchAll = (tzids == null) || (tzids.length == 0);
+
     try {
-      if ((tzids == null) || (tzids.length == 0)) {
+      if (fetchAll) {
         tzdefs = util.fetchDefs(null, null);
       } else {
         tzdefs = new ArrayList<TimezoneDef>();
@@ -119,28 +116,34 @@
     }
   }
 
+  // ical can be picky about line endings.
+  private static String newline = "\r\n";
+
+  private static String calHdr = "BEGIN:VCALENDAR" + newline +
+                                 "PRODID:-//TzService//1.0//EN" + newline +
+                                 "VERSION:2.0" + newline +
+                                 "CALSCALE:GREGORIAN" + newline;
+
   private void makeVcalendar(HttpServletResponse resp,
                              Collection<TimezoneDef> tzdefs) throws ServletException {
     try {
       PrintWriter wtr = resp.getWriter();
 
-      // ical can be picky about line endings.
-      String newline = "\r\n";
+      wtr.write(calHdr);
 
-      wtr.write("BEGIN:VCALENDAR");
-      wtr.write(newline);
-      wtr.write("PRODID:-//TzService//1.0//EN\n");
-      wtr.write(newline);
-      wtr.write("VERSION:2.0\n");
-      wtr.write(newline);
-      wtr.write("CALSCALE:GREGORIAN\n");
-      wtr.write(newline);
-
       for (TimezoneDef def: tzdefs) {
-        TimezoneInfo tzinfo = XmlToV.parseXml(def.tzDef);
+        TimezoneInfo tzinfo = TzServerUtil.getCachedVtz(def.getPrefixedId());
 
+        if (tzinfo == null) {
+          tzinfo = XmlToV.parseXml(def.tzDef);
+
+          if (tzinfo != null) {
+            TzServerUtil.putCachedVtz(tzinfo);
+          }
+        }
+
         if (tzinfo != null) {
-          wtr.write(tzinfo.tz.toString());
+          wtr.write(tzinfo.getStringTzValue());
         }
       }
 

Modified: trunk/tzsvr/src/org/bedework/timezones/server/TzServer.java
===================================================================
--- trunk/tzsvr/src/org/bedework/timezones/server/TzServer.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzsvr/src/org/bedework/timezones/server/TzServer.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -85,16 +85,16 @@
 
       String propVal = props.getProperty(TzServerUtil.pnameDerbySystemHome);
       if (propVal == null) {
-        propVal =sysp.getProperty("user.home");
+        propVal = sysp.getProperty("user.home");
 
         if (propVal == null) {
           error("No home");
           throw new ServletException("No derby system home");
         }
-
-        sysp.put(TzServerUtil.pnameDerbySystemHome, propVal);
       }
 
+      sysp.put(TzServerUtil.pnameDerbySystemHome, propVal);
+
       Long propLong = TzServerUtil.longProp(props,
                                             TzServerUtil.pnameRegistryRefetchInterval);
       if (propLong == null) {
@@ -113,8 +113,18 @@
       propLong *= 1000;
       props.put(TzServerUtil.pnameRegistryRetryInterval, propLong);
 
-      propVal = props.getProperty(TzServerUtil.pnameTzsvcRefreshOnInit);
-      if ((propVal != null) && "true".equals(propVal)) {
+      if (TzServerUtil.boolProp(props,TzServerUtil.pnameTzsvcRootProvider)) {
+        if (!TzServerUtil.boolProp(props,TzServerUtil.pnameTzsvcRootUseDb)) {
+          /* We need a root url */
+          propVal = props.getProperty(TzServerUtil.pnameTzsvcRootUrl);
+          if (propVal == null) {
+            error("No root url");
+            throw new ServletException("No root provider url");
+          }
+        }
+      }
+
+      if (TzServerUtil.boolProp(props,TzServerUtil.pnameTzsvcRefreshOnInit)) {
         TzServerUtil.refresh(props, debug);
       }
     } catch (ServletException se) {
@@ -137,6 +147,9 @@
       if (methodName.equals("OPTIONS")) {
         new OptionsMethod(debug).doMethod(req, resp, props);
       } else if (methodName.equals("GET")) {
+        if (TzServerUtil.refreshDue(props)) {
+          TzServerUtil.refresh(props, debug);
+        }
         new GetMethod(debug).doMethod(req, resp, props);
       } else if (methodName.equals("POST")) {
         new PostMethod(debug).doMethod(req, resp, props);
@@ -158,18 +171,19 @@
    *
    * @param req
    */
+  @SuppressWarnings("unchecked")
   public void dumpRequest(HttpServletRequest req) {
     Logger log = getLogger();
 
     try {
-      Enumeration names = req.getHeaderNames();
+      Enumeration<String> names = req.getHeaderNames();
 
       String title = "Request headers";
 
       log.debug(title);
 
       while (names.hasMoreElements()) {
-        String key = (String)names.nextElement();
+        String key = names.nextElement();
         String val = req.getHeader(key);
         log.debug("  " + key + " = \"" + val + "\"");
       }
@@ -193,7 +207,7 @@
       log.debug(title);
 
       while (names.hasMoreElements()) {
-        String key = (String)names.nextElement();
+        String key = names.nextElement();
         String val = req.getParameter(key);
         log.debug("  " + key + " = \"" + val + "\"");
       }

Modified: trunk/tzsvr/src/org/bedework/timezones/server/TzServerUtil.java
===================================================================
--- trunk/tzsvr/src/org/bedework/timezones/server/TzServerUtil.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzsvr/src/org/bedework/timezones/server/TzServerUtil.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -26,6 +26,11 @@
 
 package org.bedework.timezones.server;
 
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+
+import org.bedework.timezones.tzutil.TimezoneInfo;
 import org.bedework.timezones.tzutil.TimezoneProvider;
 import org.bedework.timezones.tzutil.TzUtil;
 
@@ -52,6 +57,9 @@
   /** We use derby to store data - property defining location of the files */
   public static final String pnameDerbySystemHome = "derby.system.home";
 
+  /** Database name we use */
+  public static final String pnameDbName = "tzsvc.database.name";
+
   /** Property defining location of the registry */
   public static final String pnameRegistryUrl = "tzsvc.registry.url";
 
@@ -71,6 +79,23 @@
   /** Property defining a preferred provider for this server */
   public static final String pnamePreferredProvider = "tzsvc.preferred.provider";
 
+  /** True if this server is a root server - in this case we serve up the preferred
+   * provider to others. */
+  public static final String pnameTzsvcRootProvider = "tzsvc.root.provider";
+
+  /** If this server is a root server this indicates we are using a db
+   * maintained externally for our own data */
+  public static final String pnameTzsvcRootUseDb = "tzsvc.root.use.db";
+
+  /** If this server is a root server and we are not using an externally maintained
+   * db we use this (possibly private) URL to fetch the xml formatted data */
+  public static final String pnameTzsvcRootUrl = "tzsvc.root.url";
+
+  /** True if this server is a root server only - that is it does not serve up
+   * other provider data.
+   */
+  public static final String pnameTzsvcRootOnly = "tzsvc.root.only";
+
   /** Internal use: a collection of provider info */
   public static final String pnameProviderMap = "tzsvc.provider.map";
 
@@ -81,6 +106,10 @@
    */
   public static final String pnameTzsvcRefreshOnInit = "tzsvc.refresh.on.init";
 
+  /** name of vtimezone cache
+   */
+  public static final String pnameVtzCache = "tzsvc.vtimezones.cache.name";
+
   /* ======================= Error codes ======================= */
 
   /** Unable to retrieve the registry */
@@ -89,6 +118,10 @@
   /** Time we last fetched the registry */
   public volatile static long lastRegistryFetch;
 
+  private static CacheManager manager = new CacheManager();
+
+  private static Cache vtzCache;
+
   /** Set up a Properties from the resources
    *
    * @param servlet
@@ -97,7 +130,7 @@
    * @throws ServletException
    */
   static Properties getResources(HttpServlet servlet,
-                                        ServletConfig config) throws ServletException {
+                                 ServletConfig config) throws ServletException {
     String resname = config.getInitParameter("application");
 
     Properties props = new Properties();
@@ -119,6 +152,8 @@
       }
     }
 
+    cacheInit(props);
+
     return props;
   }
 
@@ -168,56 +203,162 @@
    * @throws ServletException
    */
   static void refresh(Properties props, boolean debug) throws ServletException {
-    logIt("Refreshing the server");
+    try {
+      logIt("Refreshing the server");
 
-    /* ============= First get the registry ================= */
+      /* ============= First get the registry ================= */
 
-    TzUtil util = new TzUtil(debug);
+      TzUtil util = new TzUtil(props.getProperty(TzServerUtil.pnameDbName), debug);
 
-    Map<String, TimezoneProvider> tps =
-      (Map<String, TimezoneProvider>)props.get(pnameProviderMap);
+      Map<String, TimezoneProvider> tps = getMap(props);
 
-    if (tps == null) {
-      /* Not in properties - fetch from server */
-      tps = getRegistry(props, util);
+      if (tps == null) {
+        /* Not in properties - fetch from server */
+        tps = getRegistry(props, util);
 
-      if (tps == null) {
-        error("Unable to fetch registry.");
-        throw new ServletException(errorNoRegistry);
+        if (tps == null) {
+          error("Unable to fetch registry.");
+          throw new ServletException(errorNoRegistry);
+        }
       }
-    }
 
-    /* ============= For each provider - refresh their data ================= */
+      /* ============= For each provider - refresh their data ================= */
 
-    try {
-      for (TimezoneProvider tp: tps.values()) {
+      /* If this is the root provider we behave differently for our own prefix.
+       * We either fetch the data from a supplied url or we are serving out of a
+       * database which is updated externally in which case we do nothing.
+       *
+       * In addition, as a root server we refresh the data from other providers.
+       */
+
+      String ourPrefix = props.getProperty(TzServerUtil.pnamePreferredProvider);
+      boolean rootServer = false;
+      boolean onlyOurs = false;
+      boolean fromDb = false;
+      String rootUrl = null;
+
+      if (boolProp(props, pnameTzsvcRootProvider)) {
+        rootServer = true;
+        onlyOurs = boolProp(props,TzServerUtil.pnameTzsvcRootOnly);
+
+        if (boolProp(props,TzServerUtil.pnameTzsvcRootUseDb)) {
+          fromDb = true;
+        } else {
+          rootUrl = props.getProperty(TzServerUtil.pnameTzsvcRootUrl);
+        }
+      }
+
+      if (rootServer && !fromDb) {
+        /* Refresh from a given url. */
+        TimezoneProvider tp = new TimezoneProvider(ourPrefix,
+                                                   rootUrl, null);
         TzUtil.RefreshStatus rs = util.refresh(tp);
 
-        if (rs == TzUtil.RefreshStatus.OK) {
+        if (rs != TzUtil.RefreshStatus.OK) {
+          retryOrReschedule(props, debug);
+          return;
+        }
+      }
+
+      if (onlyOurs) {
+        // No refresh for anybody else
+
+        cacheRefresh();
+        return;
+      }
+
+      for (TimezoneProvider tp: tps.values()) {
+        if (rootServer && ourPrefix.equals(tp.prefix)) {
+          // Skip our entry
           continue;
         }
 
-        /* This could be network or bad data or a bad url. If we just refetched
-         * the registry we'll ignore it for the moment and schedule a refetch
-         * just after the registry refetch interval.
-         */
+        TzUtil.RefreshStatus rs = util.refresh(tp);
 
-        Long regRefetchInterval = (Long)props.get(pnameRegistryRefetchInterval);
-        if ((System.currentTimeMillis() - lastRegistryFetch) > regRefetchInterval) {
-          props.remove(pnameProviderMap);
-          refresh(props, debug);
-          return;
+        if (rs == TzUtil.RefreshStatus.OK) {
+          continue;
         }
 
-        /* We refetched not long ago. Reschedule */
+        retryOrReschedule(props, debug);
+        break;
+      }
 
-        // TODO
-      }
+      cacheRefresh();
     } catch (Throwable t) {
       throw new ServletException(t);
     }
   }
 
+  /* ====================================================================
+   *                   Caching
+   * ==================================================================== */
+
+  static void cacheInit(Properties props) throws ServletException {
+    vtzCache = manager.getCache(props.getProperty(pnameVtzCache));
+  }
+
+  static void cacheRefresh() throws ServletException {
+    cacheRefresh(vtzCache);
+  }
+
+  static TimezoneInfo getCachedVtz(String name) throws ServletException {
+    Element el = vtzCache.get(name);
+
+    if (el == null) {
+      return null;
+    }
+
+    return (TimezoneInfo)el.getValue();
+  }
+
+  static void putCachedVtz(TimezoneInfo vtz) throws ServletException {
+    Element el = new Element(vtz.name, vtz);
+
+    vtzCache.put(el);
+  }
+
+  /* ====================================================================
+   *                   Private methods
+   * ==================================================================== */
+
+  private static void cacheRefresh(Cache cache) throws ServletException {
+    if (cache != null) {
+      cache.flush();
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private static Map<String, TimezoneProvider> getMap(Properties props) {
+    return (Map<String, TimezoneProvider>)props.get(pnameProviderMap);
+  }
+
+  static boolean refreshDue(Properties props) {
+    Long regRefetchInterval = (Long)props.get(pnameRegistryRefetchInterval);
+    if ((System.currentTimeMillis() - lastRegistryFetch) > regRefetchInterval) {
+      return true;
+    }
+
+    return false;
+  }
+
+  private static void retryOrReschedule(Properties props,
+                                        boolean debug) throws Throwable {
+    /* This could be network or bad data or a bad url. If we just refetched
+     * the registry we'll ignore it for the moment and schedule a refetch
+     * just after the registry refetch interval.
+     */
+
+    if (refreshDue(props)) {
+      props.remove(pnameProviderMap);
+      refresh(props, debug);
+      return;
+    }
+
+    /* We refetched not long ago. Reschedule */
+
+    // TODO
+  }
+
   static Long longProp(Properties props, String name) throws Throwable {
     String propVal = props.getProperty(name);
     if (propVal == null) {
@@ -227,6 +368,15 @@
     return Long.valueOf(propVal);
   }
 
+  static boolean boolProp(Properties props, String name) throws Throwable {
+    String propVal = props.getProperty(name);
+    if (propVal == null) {
+      return false;
+    }
+
+    return Boolean.valueOf(propVal);
+  }
+
   /**
    * @return Logger
    */

Added: trunk/tzsvr/war/WEB-INF/classes/ehcache.xml
===================================================================
--- trunk/tzsvr/war/WEB-INF/classes/ehcache.xml	                        (rev 0)
+++ trunk/tzsvr/war/WEB-INF/classes/ehcache.xml	2008-07-24 19:43:24 UTC (rev 30)
@@ -0,0 +1,29 @@
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="ehcache.xsd">
+  <diskStore path="java.io.tmpdir"/>
+
+  <!--
+    Sample cache named sampleCache2
+    This cache has a maximum of 1000 elements in memory. There is no overflow to disk, so 1000
+    is also the maximum cache size. Note that when a cache is eternal, timeToLive and
+    timeToIdle are not used and do not need to be specified.
+    -->
+  <defaultCache maxElementsInMemory="10000"
+                eternal="false"
+                timeToIdleSeconds="120"
+                timeToLiveSeconds="120"
+                overflowToDisk="true"
+                diskSpoolBufferSizeMB="30"
+                maxElementsOnDisk="10000000"
+                diskPersistent="false"
+                diskExpiryThreadIntervalSeconds="120"
+                memoryStoreEvictionPolicy="LRU"
+                />
+
+  <cache name="vtz"
+         maxElementsInMemory="1000"
+         eternal="true"
+         overflowToDisk="false"
+         memoryStoreEvictionPolicy="FIFO"
+         />
+</ehcache>

Modified: trunk/tzsvr/war/WEB-INF/classes/servlet.properties
===================================================================
--- trunk/tzsvr/war/WEB-INF/classes/servlet.properties	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzsvr/war/WEB-INF/classes/servlet.properties	2008-07-24 19:43:24 UTC (rev 30)
@@ -10,6 +10,9 @@
 # We use derby to store data - property defining location of the files
 derby.system.home=$TOMCAT_HOME/../derbyhome
 
+# Database name we use
+tzsvc.database.name=tzdb
+
 # Property defining integer seconds retry interval for registry fetches
 # on registry fetch failure
 tzsvc.registry.retry.interval=60
@@ -22,10 +25,32 @@
 tzsvc.post.id=12345abcde
 
 # Property defining a preferred provider for this server
-tzsvc.preferred.provider=/OLSON
+tzsvc.preferred.provider=/EXAMPLE
 
+# True if this server is a root server - in this case we serve up the preferred
+# provider to others.
+tzsvc.root.provider=yes
+
+# If this server is a root server this indicates we are using a db
+# maintained externally for our own data
+tzsvc.root.use.db=true
+
+# If this server is a root server and we are not using an externally maintained
+# db we use this (possibly private) URL to fetch the xml formatted data
+tzsvc.root.url=http://localhost:9090/olsontzs
+
+# True if this server is a root server only - that is it does not serve up
+# other provider data.
+tzsvc.root.only=no
+
 # If true the server can refresh on init. This must be false for a root server
 # fetching from it's own applcation server or deadlock will result.
 #
 # Such a server needs an explicit POST after startup
 tzsvc.refresh.on.init=false
+
+# =========================================================================
+# Caching information - most of this is in ehcache.xml
+# =========================================================================
+
+tzsvc.vtimezones.cache.name=vtz

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/Reader.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/Reader.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/Reader.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -108,11 +108,13 @@
     Collection<TimezoneChange> tzChanges = null;
 
     PropertyList pl = tz.getProperties();
+    String name = null;
 
     while (nextStart()) {
       if (tzid.equals(rdr.getName())) {
         rdr.next();
-        pl.add(new TzId(rdr.getText()));
+        name = rdr.getText();
+        pl.add(new TzId(name));
         continue;
       }
 
@@ -154,7 +156,7 @@
       debugMsg(tz.toString());
     }
 
-    tzs.add(new TimezoneInfo(tz, tzChanges));
+    tzs.add(new TimezoneInfo(name, tz, tzChanges));
 
     return true;
   }

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneChange.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneChange.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneChange.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -1,5 +1,7 @@
 package org.bedework.timezones.tzutil;
 
+import java.io.Serializable;
+
 import net.fortuna.ical4j.model.PeriodList;
 import net.fortuna.ical4j.model.property.DtStamp;
 
@@ -7,7 +9,7 @@
  *
  * @author Mike Douglass
  */
-public class TimezoneChange implements Comparable<TimezoneChange> {
+public class TimezoneChange implements Comparable<TimezoneChange>, Serializable {
   /** Date the change was made - these are ordered
    */
   public DtStamp dateStamp;

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneDef.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneDef.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneDef.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -1,12 +1,13 @@
 package org.bedework.timezones.tzutil;
 
+import java.io.Serializable;
 import java.util.Collection;
 
 /** Timezone definition saved and extracted from db
  *
  * @author Mike Douglass
  */
-public class TimezoneDef {
+public class TimezoneDef implements Serializable {
   /** The timezone prefix
    */
   public String tzPrefix;
@@ -38,4 +39,8 @@
     this.tzAliases = tzAliases;
     this.tzDef = tzDef;
   }
+
+  public String getPrefixedId() {
+    return tzPrefix + "/" + tzId;
+  }
 }
\ No newline at end of file

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneInfo.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneInfo.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneInfo.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -2,13 +2,18 @@
 
 import net.fortuna.ical4j.model.component.VTimeZone;
 
+import java.io.Serializable;
 import java.util.Collection;
 
 /** Timezone spec and related changes.
  *
  * @author Mike Douglass
  */
-public class TimezoneInfo {
+public class TimezoneInfo implements Serializable {
+  /** Prefix id
+   */
+  public String name;
+
   /** The timezone spec
    */
   public VTimeZone tz;
@@ -17,13 +22,23 @@
    */
   public Collection<TimezoneChange> changes;
 
+  /* Vlaue of tz */
+  private String stringTzValue;
+
   /**
    * @param tz
    * @param changes
    */
-  public TimezoneInfo(VTimeZone tz,
+  public TimezoneInfo(String name,
+                      VTimeZone tz,
                       Collection<TimezoneChange> changes) {
+    this.name = name;
     this.tz = tz;
     this.changes = changes;
+    stringTzValue = tz.toString();
   }
+
+  public String getStringTzValue() {
+    return stringTzValue;
+  }
 }
\ No newline at end of file

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneProvider.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneProvider.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/TimezoneProvider.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -26,4 +26,18 @@
     this.url = url;
     this.contact = contact;
   }
+
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+
+    sb.append("TimezoneProvider{prefix=");
+    sb.append(prefix);
+    sb.append(", url=");
+    sb.append(url);
+    sb.append(", contact=");
+    sb.append(contact);
+    sb.append("}");
+
+    return sb.toString();
+  }
 }
\ No newline at end of file

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/TzUtil.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/TzUtil.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/TzUtil.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -40,6 +40,8 @@
 public class TzUtil {
   private boolean debug;
 
+  private String dbName;
+
   private Connection conn;
 
   private boolean stayOpen;
@@ -60,6 +62,11 @@
     this.debug = debug;
   }
 
+  public TzUtil(String dbName, boolean debug) {
+    this.dbName = dbName;
+    this.debug = debug;
+  }
+
   /**
    * @param registryUrl
    * @return collection
@@ -213,6 +220,13 @@
       }
 
       return RefreshStatus.OK;
+    } catch (Throwable t) {
+      error("Unable to access " + tp);
+      if (debug) {
+        t.printStackTrace();
+      }
+
+      return RefreshStatus.NOCONNECTION;
     } finally {
       close();
     }
@@ -230,13 +244,17 @@
    * @throws Throwable
    */
   public void connect(boolean stayOpen) throws Throwable {
+    if (dbName == null) {
+      throw new Exception("No dbName");
+    }
+
     if (conn != null) {
       throw new Exception("Already open");
     }
 
     try {
       String driver = "org.apache.derby.jdbc.EmbeddedDriver";
-      String url = "jdbc:derby:tzdb;create=true";
+      String url = "jdbc:derby:" + dbName + ";create=true";
 
       try {
         Class.forName(driver);

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/VtoXml.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/VtoXml.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/VtoXml.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -71,6 +71,10 @@
 
   private String dirName;
 
+  private String dbName = "tzdb";
+
+  private String derbySystemHome;
+
   private File inDir;
   private StringWriter out;
 
@@ -98,10 +102,16 @@
   void open() throws Throwable {
     inDir = new File(dirName);
 
-    tzutil = new TzUtil(debug);
+    tzutil = new TzUtil(dbName, debug);
 
     if (clean) {
-      tzutil.dropAll();
+      File f = new File(derbySystemHome + "/" + dbName);
+
+      if (f.exists()) {
+        throw new Exception("Delete " + derbySystemHome + "/" + dbName +
+                            " and rerun");
+      }
+
       tzutil.createDb();
     }
 
@@ -117,6 +127,7 @@
 
   void close(boolean ok) throws Throwable {
     if (tzutil == null) {
+      warn("No conversion?");
       return;
     }
 
@@ -126,13 +137,14 @@
     }
 
     if (initDb) {
-      // We were updating a prefix
+      // We were updating a prefix and failed
+      warn("Error in conversion?");
       tzutil.close();
     }
 
     long ct = tzutil.countDefs();
 
-    info("Created: " + ct);
+    info("Conversion complete, created: " + ct);
   }
 
   void stats() throws Throwable {
@@ -372,13 +384,14 @@
       return true;
     }
 
-    String derbySystemHome = null;
-
     for (int i = 0; i < args.length; i++) {
       if (args[i].equals("-debug")) {
         debug = true;
       } else if (args[i].equals("-ndebug")) {
         debug = false;
+      } else if (argpar("-db", args, i)) {
+        i++;
+        dbName = args[i];
       } else if (argpar("-dir", args, i)) {
         i++;
         dirName = args[i];
@@ -436,10 +449,10 @@
         usage();
         return false;
       }
-
-      p.put("derby.system.home", derbySystemHome);
     }
 
+    p.put("derby.system.home", derbySystemHome);
+
     info("derbySystemHome=" + derbySystemHome);
 
     return true;
@@ -457,6 +470,8 @@
     System.out.println("            update the db - if not specified we just validate");
     System.out.println("       -dir dirname");
     System.out.println("            directory containing timezone defs");
+    System.out.println("       -dsh dirname");
+    System.out.println("            derby db home directory");
     System.out.println("       -prefix prefix");
     System.out.println("            prefix for timezone ids with leading '/'");
     System.out.println("If -update is specified clean or init must be specified ");
@@ -491,6 +506,10 @@
     getLog().error(msg);
   }
 
+  protected void warn(String msg) {
+    getLog().warn(msg);
+  }
+
   protected void trace(String msg) {
     getLog().debug(msg);
   }

Modified: trunk/tzutil/src/org/bedework/timezones/tzutil/XmlToV.java
===================================================================
--- trunk/tzutil/src/org/bedework/timezones/tzutil/XmlToV.java	2008-07-02 04:02:42 UTC (rev 29)
+++ trunk/tzutil/src/org/bedework/timezones/tzutil/XmlToV.java	2008-07-24 19:43:24 UTC (rev 30)
@@ -57,6 +57,7 @@
 import org.w3c.dom.Node;
 import org.xml.sax.InputSource;
 
+import java.io.StringReader;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -70,8 +71,12 @@
  *
  */
 public class XmlToV implements TzDefs {
+  private static XmlToV parser =new XmlToV();
+
   private boolean debug = true;
 
+  private boolean verbose = false;
+
   /** Parse a single timezone definition delivered as a String value and
    * return the TimeZoneInfo object for the specification.
    *
@@ -81,15 +86,15 @@
    */
   public static TimezoneInfo parseXml(String xmlData) throws Throwable {
     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-    factory.setNamespaceAware(false);
+    factory.setNamespaceAware(true);
 
     DocumentBuilder builder = factory.newDocumentBuilder();
 
-    Document doc = builder.parse(new InputSource(xmlData));
+    Document doc = builder.parse(new InputSource(new StringReader(xmlData)));
 
     Element root = doc.getDocumentElement();
 
-    return new XmlToV().parseXml(root);
+    return parser.parseXml(root);
   }
 
   /**
@@ -103,6 +108,7 @@
     }
 
     VTimeZone tz = new VTimeZone();
+    String name = null;
     Collection<TimezoneChange> tzChanges = null;
 
     PropertyList pl = tz.getProperties();
@@ -110,7 +116,8 @@
     Element[] tzNodes = TzUtil.getElementsArray(tzEl);
     for (Element el: tzNodes) {
       if (TzUtil.nodeMatches(el, tzid)) {
-        pl.add(new TzId(TzUtil.getElementContent(el)));
+        name = TzUtil.getElementContent(el);
+        pl.add(new TzId(name));
         continue;
       }
 
@@ -151,7 +158,7 @@
       debugMsg(tz.toString());
     }
 
-    return new TimezoneInfo(tz, tzChanges);
+    return new TimezoneInfo(name, tz, tzChanges);
   }
 
   private Collection<TimezoneChange> parseChanges(Element chgsEl) throws Throwable {
@@ -167,7 +174,7 @@
       String desc = null;
       PeriodList affectedlist = null;
 
-      if (debug) {
+      if (debug && verbose) {
         debugMsg("parseChanges: start-change");
       }
 
@@ -258,7 +265,7 @@
 
     Observance ob = null;
 
-    if (debug) {
+    if (debug && verbose) {
       debugMsg("parseObservance: start");
     }
 
@@ -387,27 +394,27 @@
 
     for (int i = 0; i < attrCt; i++) {
       Node attr = nnm.item(i);
-      if (debug) {
+      if (debug && verbose) {
         debugMsg("attr: " + attr);
       }
 
-      if (TzUtil.nodeMatches(el, date)) {
+      if (TzUtil.nodeMatches(attr, date)) {
         // Equivalent to RDATE
         dateVal = attr.getNodeValue();
         continue;
       }
 
-      if (TzUtil.nodeMatches(el, month)) {
+      if (TzUtil.nodeMatches(attr, month)) {
         bymonthVal = attr.getNodeValue();
         continue;
       }
 
-      if (TzUtil.nodeMatches(el, monthday)) {
+      if (TzUtil.nodeMatches(attr, monthday)) {
         bymonthdayVal = attr.getNodeValue();
         continue;
       }
 
-      if (TzUtil.nodeMatches(el, day)) {
+      if (TzUtil.nodeMatches(attr, day)) {
         bydayVal = attr.getNodeValue();
         continue;
       }



More information about the Bedework-commit mailing list