Print

Print


Commit in LCGO on MAIN
GNUmakefile+68added 1.1
GeometryReaderTest.xml+222added 1.1
test.cc+17added 1.1
src/cpp/LCGO.cc+18added 1.1
       /LCGOUtil.cc+15added 1.1
src/include/LCGO.h+22added 1.1
           /LCGOUtil.h+11added 1.1
src/java/hep/lcgo/util/cache/ByteFormat.java+71added 1.1
                            /FileCache.java+208added 1.1
src/java/hep/lcgo/xml/reader/Constant.java+46added 1.1
                            /Detector.java+75added 1.1
                            /Header.java+110added 1.1
                            /LCGOElementFactory.java+20added 1.1
                            /LCGOReader.java+117added 1.1
                            /package.html+7added 1.1
src/java/hep/lcgo/xml/reader/util/CachingEntityResolver.java+38added 1.1
                                 /DefaultElementFactory.java+100added 1.1
                                 /ElementFactory.java+28added 1.1
                                 /JDOMExpressionFactory.java+161added 1.1
+1354
19 added files


LCGO
GNUmakefile added at 1.1
diff -N GNUmakefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ GNUmakefile	29 Sep 2006 16:27:16 -0000	1.1
@@ -0,0 +1,68 @@
+JDOM=jdom-1.0.jar
+JEL=jel-0.9.10.jar
+XERCES=xercesImpl-2.8.0.jar
+
+WORK=/tmp/work
+DIST=/tmp/dist
+
+CLASSPATH=$(WORK)/jars/$(JDOM):$(WORK)/jars/$(JEL)
+
+.PHONY : all
+all: test
+                
+$(WORK)/jars/$(JDOM): 
+	mkdir -p $(WORK)/jars
+	wget -P $(WORK)/jars http://www.ibiblio.org/maven/jdom/jars/$(JDOM) 
+
+$(WORK)/jars/$(JEL):
+	mkdir -p $(WORK)/jars
+	wget -P $(WORK)/jars http://java.freehep.org/maven/jel/jars/$(JEL) 
+
+$(WORK)/jars/$(XERCES):
+	mkdir -p $(WORK)/jars
+	wget -P $(WORK)/jars http://www.ibiblio.org/maven/xerces/jars/$(XERCES) 
+
+$(DIST)/lib/%.jar.so : $(WORK)/jars/%.jar
+	mkdir -p $(DIST)/lib
+	gcj -fPIC -findirect-dispatch -shared -o $@ $<
+
+# Not currently used
+%.jar.a : %.jar
+	gcj -c -findirect-dispatch  -o $<.o $<
+	ar rcs $@ $<.o
+	rm $<.o
+        
+$(DIST)/include/hep/lcgo/xml/reader/%.h: $(WORK)/jars/LCGO.jar
+	mkdir -p $(DIST)/include/hep/lcgo/xml/reader
+	gcjh --classpath=$< -d $(DIST)/include hep.lcgo.xml.reader.$*
+
+$(WORK)/jars/LCGO.jar: src/java/hep/lcgo/xml/reader/*.java src/java/hep/lcgo/xml/reader/util/*.java src/java/hep/lcgo/util/cache/*.java
+	mkdir -p $(WORK)/classes
+	gcj -d $(WORK)/classes --classpath=$(CLASSPATH) -C $^
+	fastjar -cf $@ -C $(WORK)/classes .
+        
+$(WORK)/includes: src/include/* $(DIST)/include/hep/lcgo/xml/reader/LCGOReader.h $(DIST)/include/hep/lcgo/xml/reader/Detector.h $(DIST)/include/hep/lcgo/xml/reader/Constant.h
+	cp -r src/include/*.h $(DIST)/include
+	touch $@
+	
+$(WORK)/dist: $(DIST)/lib/$(XERCES).so $(DIST)/lib/$(JDOM).so $(DIST)/lib/$(JEL).so $(DIST)/lib/LCGO.jar.so $(DIST)/lib/LCGO.so $(WORK)/includes
+	touch $@
+
+$(DIST)/lib/LCGO.so: src/cpp/*.cc $(WORK)/includes
+	gcj -o $@ -fPIC -shared -I$(DIST)/include src/cpp/*.cc  
+
+test: test.cc $(WORK)/dist
+	g++ -o $@ -I$(DIST)/include $< $(DIST)/lib/*.so -lgcj
+
+.PHONY : run
+run: test
+	./test
+
+
+.PHONY : clean
+clean:
+	-rm -rf $(WORK) 
+	-rm -rf $(DIST)
+	-rm test
+
+

LCGO
GeometryReaderTest.xml added at 1.1
diff -N GeometryReaderTest.xml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ GeometryReaderTest.xml	29 Sep 2006 16:27:16 -0000	1.1
@@ -0,0 +1,222 @@
+<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0"
+       xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
+       xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">
+
+  <!-- info tag containing author, version, time, unique id (url) -->
+  <info name="GeometryReaderTest">
+    <comment>
+      Test of org.lcsim.geometry.GeometryReader
+    </comment>
+  </info>
+
+  <!-- Constants -->
+  <define>
+  
+    <constant name="cm" value="10"/>  
+
+    <!-- world -->
+    <constant name="world_side" value="15000" />
+    <constant name="world_x" value="world_side" />
+    <constant name="world_y" value="world_side" />
+    <constant name="world_z" value="world_side" />
+    
+    <!-- tracking region -->
+    <constant name="tracking_region_radius" value="127.0*cm"/>
+    <constant name="tracking_region_zmax" value="168.0*cm"/>
+    
+    <constant name="vertex_inner_r" value="1.2*cm"/>
+    <constant name="vertex_delta_r" value="1.2*cm"/>
+    <constant name="vertex_outer_z" value="12.5*cm"/>
+    
+  </define>
+
+  <materials>
+
+      <!-- so can easily replace references 
+	   with something more realistic later -->
+      <material name="MuonAir">
+	<D type="density" unit="g/cm3" value="0.0012"/>
+	<fraction n="0.7803"  ref="N"/>
+	<fraction n="0.2103"  ref="O"/>
+	<fraction n="0.0094"  ref="Ar"/>
+      </material>
+
+  </materials>
+  
+  <detectors>
+      <detector id="1" name="VertexBarrel" type="MultiLayerTracker" readout="VtxBarrHits">
+          <layer id="1" inner_r = "vertex_inner_r" outer_z = "2.5*cm">
+                <slice material = "Silicon" thickness = "0.01*cm" sensitive = "yes" />
+          </layer>
+          <layer id="2" inner_r = "vertex_inner_r + 1 * vertex_delta_r" outer_z = "vertex_outer_z">
+                <slice material = "Silicon" thickness = "0.01*cm" sensitive = "yes" />
+          </layer>
+          <layer id="3" inner_r = "vertex_inner_r + 2 * vertex_delta_r" outer_z = "vertex_outer_z">
+                <slice material = "Silicon" thickness = "0.01*cm" sensitive = "yes" />
+          </layer>
+          <layer id="4" inner_r = "vertex_inner_r + 3 * vertex_delta_r" outer_z = "vertex_outer_z" >
+                <slice material = "Silicon" thickness = "0.01*cm" sensitive = "yes" />
+          </layer>
+          <layer id="5" inner_r = "vertex_inner_r + 4 * vertex_delta_r" outer_z = "vertex_outer_z">
+                <slice material = "Silicon" thickness = "0.01*cm" sensitive = "yes" />
+          </layer>
+     </detector>
+      
+     <detector id="2" name="BarrelTracker" type="MultiLayerTracker" readout="TkrBarrHits">
+          <layer id="1" inner_r = "20.0*cm" outer_z = "26.67*cm">
+                <slice material = "G10" thickness = "0.05*cm" />
+                <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+          </layer>
+          <layer id="2" inner_r = "46.25*cm" outer_z = "61.67*cm">
+                <slice material = "G10" thickness = "0.05*cm" />
+                <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+          </layer>
+          <layer id="3" inner_r = "72.5*cm" outer_z = "96.67*cm">
+                <slice material = "G10" thickness = "0.05*cm" />
+                <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+          </layer>
+          <layer id="4" inner_r = "98.75*cm" outer_z = "131.67*cm" >
+                <slice material = "G10" thickness = "0.05*cm" />
+                <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+          </layer>
+          <layer id="5" inner_r = "125.0*cm" outer_z = "166.67*cm">
+                <slice material = "G10" thickness = "0.05*cm" />
+                <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+          </layer>
+     </detector>
+     
+     <detector id="3" name="EndcapTracker" type="DiskTracker" reflect="true" readout="TkrEndcapHits">
+        <layer id="1" inner_r = "4.0*cm" inner_z = "27.1*cm" outer_r = "20.50*cm">
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>
+        <layer id="2" inner_r = "4.0*cm" inner_z = "27.12*cm" outer_r = "20.50*cm">
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>    
+        <layer id="3" inner_r = "7.9*cm" inner_z = "62.1*cm" outer_r = "46.75*cm">
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>           
+        <layer id="4" inner_r = "7.9*cm" inner_z = "62.12*cm" outer_r = "46.75*cm" >
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer> 
+        <layer id="5" inner_r = "11.7*cm" inner_z = "97.1*cm" outer_r = "73.0*cm" >
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>  
+        <layer id="6" inner_r = "11.7*cm" inner_z = "97.12*cm" outer_r = "73.0*cm">
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>
+        <layer id="7" inner_r = "15.6*cm" inner_z = "132.1*cm" outer_r = "99.25*cm">
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>   
+        <layer id="8" inner_r = "15.6*cm" inner_z = "132.12*cm" outer_r = "99.25*cm">
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>           
+        <layer id="9" inner_r = "19.5*cm" inner_z = "167.1*cm" outer_r = "125.50*cm" >
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer> 
+        <layer id="10" inner_r = "19.5*cm" inner_z = "167.12*cm" outer_r = "125.50*cm" >
+           <slice material = "Silicon" thickness = "0.02*cm" sensitive = "yes" />
+        </layer>        
+     </detector>
+    <detector id="4" name="EMBarrel" type="CylindricalBarrelCalorimeter" readout="EcalBarrHits">  
+         <dimensions inner_r = "127.0*cm" outer_z = "184.0*cm" />
+         <layer repeat="30">
+           <slice material = "Tungsten" thickness = "0.25*cm" />
+           <slice material = "G10" thickness = "0.05*cm" />
+           <slice material = "Silicon" thickness = "0.04*cm" sensitive = "yes" />
+           <slice material = "Copper" thickness = "0.1*cm" />
+           <slice material = "Air" thickness = "0.06*cm" />
+         </layer>
+    </detector>  
+    <detector id="5" name="EMEndcap" reflect="true" type="CylindricalEndcapCalorimeter" readout="EcalEndcapHits">
+        <dimensions inner_r = "20.0*cm" inner_z = "168.0*cm" outer_r = "125.0*cm" />
+        <layer repeat="30" >
+          <slice material = "Tungsten" thickness = "0.25*cm" />
+          <slice material = "G10" thickness = "0.05*cm" />
+          <slice material = "Silicon" thickness = "0.04*cm" sensitive = "yes" />
+          <slice material = "Copper" thickness = "0.1*cm" />
+          <slice material = "Air" thickness = "0.06*cm" />
+        </layer>
+    </detector>
+    <detector id="6" name="HADBarrel" type="CylindricalBarrelCalorimeter" readout="HcalBarrHits">
+         <dimensions inner_r = "144.0*cm" outer_z = "286.0*cm" />
+         <layer repeat="34">
+           <slice material = "Steel235" thickness = "2.0*cm" />
+           <slice material = "Polystyrene" thickness = "1.0*cm" sensitive = "yes" />
+         </layer>
+    </detector>
+    <detector id="7" name="HADEndcap" reflect="true" type="CylindricalEndcapCalorimeter" readout="HcalEndcapHits">
+        <dimensions inner_r = "20.0*cm" inner_z = "184.0*cm" outer_r = "142.0*cm" />
+        <layer repeat="34" >
+           <slice material = "Steel235" thickness = "2.0*cm" />
+           <slice material = "Polystyrene" thickness = "1.0*cm" sensitive = "yes" />
+        </layer>
+    </detector> 
+    <detector id="8" name="MuonBarrel" type="CylindricalBarrelCalorimeter" readout="MuonBarrHits" detectorType="calorimeter">
+         <dimensions inner_r = "337.0*cm" outer_z = "287.0*cm" />
+         <layer repeat="32">
+           <slice material = "Iron" thickness = "5.0*cm" />
+           <slice material = "Air" thickness = "1.5*cm" sensitive = "yes" />
+         </layer>
+    </detector>  
+    <detector id="9" name="MuonEndcap"  reflect="true" type="CylindricalEndcapCalorimeter" readout="MuonEndcapHits">
+         <dimensions inner_r = "20.0*cm" inner_z = "287.0*cm" outer_r = "636.0*cm" />
+         <layer repeat="32">
+           <slice material = "Iron" thickness = "5.0*cm" />
+           <slice material = "Air" thickness = "1.5*cm" sensitive = "yes" />
+         </layer>
+    </detector>
+    <detector id="10" name="LumEndcap" reflect="true" type="CylindricalEndcapCalorimeter" readout="LumEndcapHits">
+        <dimensions inner_r = "0.0001*cm" inner_z = "310.0*cm" outer_r = "9.2*cm" />
+        <layer repeat="1">
+          <slice material="Beryllium" thickness = "10.*cm" />
+          <slice material="Tungsten" thickness = "35.*cm" sensitive = "yes" />
+        </layer>
+    </detector>  
+  </detectors>
+  <readouts>
+         <readout name="MuonBarrHits"> 
+             <segmentation type="ProjectiveCylinder" thetaBins="150" phiBins="300"/>
+             <id>layer:7,system:3,barrel:3,theta:32:11,phi:11</id>
+         </readout>
+         <readout name="MuonEndcapHits"> 
+             <segmentation type="ProjectiveZPlane" thetaBins="150" phiBins="300"/>
+             <id>layer:7,system:3,barrel:3,theta:32:11,phi:11</id>
+         </readout>
+         <readout name="LumEndcapHits"> 
+             <segmentation type="ProjectiveZPlane" thetaBins="600" phiBins="1200"/>
+             <id>layer:7,system:3,barrel:3,theta:32:11,phi:11</id>
+         </readout>
+         <readout name="HcalEndcapHits"> 
+             <segmentation type="ProjectiveZPlane" thetaBins="600" phiBins="1200"/>
+             <id>layer:7,system:3,barrel:3,theta:32:11,phi:11</id>
+         </readout>
+         <readout name="HcalBarrHits"> 
+             <segmentation type="ProjectiveCylinder" thetaBins="600" phiBins="1200"/>
+             <id>layer:7,system:3,barrel:3,theta:32:11,phi:11</id>
+         </readout>
+         <readout name="EcalEndcapHits"> 
+           <segmentation type="ProjectiveZPlane" thetaBins="840" phiBins="1680"/>
+           <id>layer:7,system:3,barrel:3,theta:32:11,phi:11</id>
+        </readout>
+         <readout name="EcalBarrHits"> 
+             <segmentation type="ProjectiveCylinder" thetaBins="840" phiBins="1680"/>
+             <id>layer:7,system:3,barrel:3,theta:32:11,phi:11</id>
+         </readout>
+         <readout name="TkrBarrHits"> 
+             <id>layer:10,system:3,barrel:3</id>
+         </readout>
+         <readout name="TkrEndcapHits"> 
+             <id>layer:10,system:3,barrel:3</id>
+         </readout>
+         <readout name="VtxBarrHits"> 
+             <id>layer:10,system:3,barrel:3</id>
+         </readout>
+   </readouts>
+   <fields>
+    <field type="Solenoid" name="GlobalSolenoid"
+              inner_field="5.0"
+              outer_field="-0.6"
+              zmax="1000"
+              outer_radius="144*cm+(2+1)*34*cm"/>
+   </fields>
+</lccdd>

LCGO
test.cc added at 1.1
diff -N test.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ test.cc	29 Sep 2006 16:27:16 -0000	1.1
@@ -0,0 +1,17 @@
+#include <iostream>
+#include "LCGO.h"
+#include "java/util/Map.h"
+
+int main(int argc, char *argv[])
+{
+    using namespace hep::lcgo::xml::reader;
+    using namespace java::util;
+    using namespace std;
+
+    LCGO lcgo("GeometryReaderTest.xml");
+    Detector* det = lcgo.getDetector();
+    Map* constants = det->getConstants();
+  
+    cout << det << endl;
+    cout << constants << endl; 
+}

LCGO/src/cpp
LCGO.cc added at 1.1
diff -N LCGO.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ LCGO.cc	29 Sep 2006 16:27:17 -0000	1.1
@@ -0,0 +1,18 @@
+#include "LCGO.h"
+
+LCGO::LCGO(char* file)
+{
+    JvCreateJavaVM(NULL);
+    JvAttachCurrentThread(NULL, NULL);
+
+    hep::lcgo::xml::reader::LCGOReader* reader = new hep::lcgo::xml::reader::LCGOReader();
+    detector = reader->read(JvNewStringLatin1(file));
+}
+hep::lcgo::xml::reader::Detector* LCGO::getDetector()
+{
+   return detector;
+}
+LCGO::~LCGO()
+{
+    JvDetachCurrentThread();
+}

LCGO/src/cpp
LCGOUtil.cc added at 1.1
diff -N LCGOUtil.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ LCGOUtil.cc	29 Sep 2006 16:27:17 -0000	1.1
@@ -0,0 +1,15 @@
+#include "LCGOUtil.h"
+
+std::ostream& operator << (std::ostream& os, const java::lang::Object* obj)
+{
+    jstring value = ((java::lang::Object*) obj)->toString();
+    int l = JvGetStringUTFLength(value);
+    char* result = (char*) JvMalloc(l+1);
+    JvGetStringUTFRegion(value,0,l,result);
+    *(result+l)='\0';
+    
+    os<<result;
+    
+    JvFree(result);
+    return os;
+}

LCGO/src/include
LCGO.h added at 1.1
diff -N LCGO.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ LCGO.h	29 Sep 2006 16:27:17 -0000	1.1
@@ -0,0 +1,22 @@
+#ifndef LCGO_INCLUDED
+#define LCGO_INCLUDED
+
+#include <gcj/cni.h>
+#include "hep/lcgo/xml/reader/LCGOReader.h"
+#include "hep/lcgo/xml/reader/Detector.h"
+#include "hep/lcgo/xml/reader/Constant.h"
+#include "LCGOUtil.h"
+
+
+
+class LCGO {
+  public:
+    LCGO(char* file);
+    ~LCGO();
+    hep::lcgo::xml::reader::Detector* getDetector();
+        
+  private:
+    hep::lcgo::xml::reader::Detector* detector;
+};
+
+#endif

LCGO/src/include
LCGOUtil.h added at 1.1
diff -N LCGOUtil.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ LCGOUtil.h	29 Sep 2006 16:27:17 -0000	1.1
@@ -0,0 +1,11 @@
+#ifndef LCGOUTIL_INCLUDED
+#define LCGOUTIL_INCLUDED
+
+#include <iostream>
+
+#include <gcj/cni.h>
+#include "java/lang/Object.h"
+
+std::ostream& operator << (std::ostream& os, const java::lang::Object* obj);
+
+#endif

LCGO/src/java/hep/lcgo/util/cache
ByteFormat.java added at 1.1
diff -N ByteFormat.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ByteFormat.java	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,71 @@
+package hep.lcgo.util.cache;
+
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+
+/**
+ * A formatter for formatting byte sizes. For example, formatting 12345 byes results in
+ * "12.1 kB" and 1234567 results in "1.18 MB".
+ *
+ * @author Bill Lynch
+ * @author Tony Johnson
+ */
+public class ByteFormat extends Format
+{
+   
+   private final static String[] mags = {" B"," kB"," MB"," GB"," TB"," PB"};
+   private final static DecimalFormat formatter = new DecimalFormat("#,##0.0");
+   /**
+    * Formats a long which represent a number of bytes.
+    */
+   public String format(long bytes)
+   {
+      return format(new Long(bytes));
+   }
+   
+   /**
+    * Format the given object (must be a Long).
+    *
+    * @param obj assumed to be the number of bytes as a Long.
+    * @param buf the StringBuffer to append to.
+    * @param pos
+    * @return A formatted string representing the given bytes in more human-readable form.
+    */
+   public StringBuffer format(Object obj, StringBuffer buf, FieldPosition pos)
+   {
+      if (obj instanceof Long)
+      {
+         long numBytes = ((Long)obj).longValue();
+         if (numBytes > 1024)
+         {
+            int mag = 1;
+            for (; mag<mags.length; mag++)
+            {
+               if (numBytes < 1024*1024) break;
+               numBytes /= 1024;
+            }
+            
+            buf.append(formatter.format((double)numBytes / 1024.0)).append(mags[mag]);
+         }
+         else
+         {
+            buf.append(numBytes).append(mags[0]);
+         }
+      }
+      return buf;
+   }
+   
+   /**
+    * In this implementation, returns null always.
+    *
+    * @param source
+    * @param pos
+    * @return returns null in this implementation.
+    */
+   public Object parseObject(String source, ParsePosition pos)
+   {
+      return null;
+   }
+}

LCGO/src/java/hep/lcgo/util/cache
FileCache.java added at 1.1
diff -N FileCache.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ FileCache.java	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,208 @@
+package hep.lcgo.util.cache;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+
+/**
+ * A utility for downloading and caching files
+ * @author tonyj
+ */
+public class FileCache
+{
+   private static final File home = new File(getCacheRoot(),".cache");
+   private static final ByteFormat format = new ByteFormat();
+   private File cache;
+   private PrintStream print = System.out;
+   
+   public static File getCacheRoot()
+   {
+      String cacheDir = System.getProperty("hep.lcgo.cacheDir");
+      if (cacheDir == null) cacheDir = System.getProperty("user.home");
+      return new File(cacheDir);
+   }
+   
+   /**
+    * Create a FileCache using the default cache location
+    * @throws java.io.IOException If the cache directory cannot be created
+    */
+   public FileCache() throws IOException
+   {
+      this(home);
+   }
+   
+   /**
+    * Create a file cache using an explicit cache location
+    * @param cacheDirectory The directory to use for storing cached files
+    * @throws java.io.IOException If the cache directory cannot be created
+    */
+   public FileCache(File cacheDirectory) throws IOException
+   {
+      setCacheDirectory(cacheDirectory);
+   }
+   /**
+    * Get a file from the cache. If the file is already in the cache and up-to-date the existing 
+    * file will be returned. Otherwise the file will be downloaded first, and then moved
+    * to the cache.
+    * @param url Teh URL of the file to download
+    * @throws java.io.IOException If the file cannot be downloaded, or if an error occurs writing to the cache.
+    * @return The location of the cached file
+    */
+   public File getCachedFile(URL url) throws IOException
+   {
+      return getCachedFile(url,null);
+   }
+   
+   /**
+    * Get a file from the cache. If the file is already in the cache and up-to-date the existing 
+    * file will be returned. Otherwise the file will be downloaded first, validated, and then moved
+    * to the cache.
+    * @param url Teh URL of the file to download
+    * @param validator A Validator that will be used to check the integrity of the downloaded file before it is 
+    * placed in the cache
+    * @throws java.io.IOException If the file cannot be downloaded, or if an error occurs writing to the cache, or if the file
+    * fails validation.
+    * @return The location of the cached file
+    */
+   public File getCachedFile(URL url, Validator validator) throws IOException
+   {
+      File cacheFile = new File(cache,URLEncoder.encode(url.toExternalForm(),"UTF-8"));
+      boolean downloadRequired = !cacheFile.exists();
+      if (cacheFile.exists() && !Boolean.getBoolean("hep.lcgo.offline"))
+      {
+         // If we can access the URL, check if the cachefile is up-to-date
+         try
+         {
+            URLConnection connection = url.openConnection();
+            //connection.setConnectTimeout(5000);
+            long updated = connection.getLastModified();
+            long cached = cacheFile.lastModified();
+            if (updated > cached) downloadRequired = true;
+         }
+         catch (IOException x)
+         {
+            // Just assume file in cache is OK.
+         }
+      }
+      if (downloadRequired)
+      {
+         URLConnection connection = url.openConnection();
+         //connection.setConnectTimeout(10000);
+         long size  = connection.getContentLength();
+         InputStream in = connection.getInputStream();
+         if (in != null)
+         {
+            if (print != null) print.println("Downloading..."+url);
+            File temp = File.createTempFile("det",null,cache);
+            temp.deleteOnExit();
+            OutputStream out = new FileOutputStream(temp);
+            byte[] buffer = new byte[8096];
+            try
+            {
+               long got = 0;
+               for (;;)
+               {
+                  int l = in.read(buffer);
+                  if (l < 0) break;
+                  out.write(buffer,0,l);
+                  if (out != null) 
+                  { 
+                     got += l;
+                     print.print("Got ");
+                     print.print(format.format(got));
+                     print.print('/');
+                     print.print(format.format(size));
+                     print.print('\r');
+                     print.flush();
+                  }
+               }
+            }
+            finally
+            {
+               in.close();
+               out.close();
+            }
+            if (validator != null) validator.checkValidity(url,temp);
+            // File looks ok, move it into the cache
+            if (cacheFile.exists())
+            {
+               boolean ok = cacheFile.delete();
+               if (!ok) throw new IOException("Error while deleting old cache file");
+            }
+            boolean ok = temp.renameTo(cacheFile);
+            if (!ok) throw new IOException("Error while moving file to cache");
+         }
+         else throw new IOException("Could not open "+url);
+      }
+      return cacheFile;
+   }
+
+
+   /**
+    * Get the directory used for caching
+    * @return The cache directory
+    */
+   public File getCacheDirectory()
+   {
+      return this.cache;
+   }
+
+   /**
+    * Set a new cache directory location
+    * @param cacheDirectory The directory to use.
+    * @throws java.io.IOException If the specified directory cannot be created, or already exists and is not a directory.
+    */
+   public void setCacheDirectory(File cacheDirectory) throws IOException
+   {
+      if (!cacheDirectory.exists())
+      {
+         boolean ok = cacheDirectory.mkdirs();
+         if (!ok) throw new IOException("Unable to create: "+cacheDirectory.getAbsoluteFile());
+      }
+      else if (!cacheDirectory.isDirectory())
+      {
+         throw new IOException("Not a directory");
+      }
+      this.cache = cacheDirectory;
+   }
+
+   /**
+    * Gets the print stream used for diagnostic messages if a file is downloaded.
+    * @return The current diagnostic print stream, or <CODE>null</CODE> if none exists.
+    */
+   public PrintStream getPrintStream()
+   {
+
+      return this.print;
+   }
+
+   /**
+    * Set the print stream to be used for diagnostic messages
+    * @param printStream The print stream to use, or <CODE>null</CODE> to disable diagnostic messages
+    */
+   public void setPrintStream(PrintStream printStream)
+   {
+      this.print = printStream;
+   }
+   /**
+    * An interface to be implemented by cache validators
+    * @see #getCachedFile(URL,Validator)
+    */
+   public static interface Validator
+   {
+      /**
+       * Called after a file has been downloaded but before it is placed in the cache,
+       * This method should throw an IOException if the file fails to validate.
+       * @param url The URL being downloaded
+       * @param file The file that needs to be validated
+       * @throws java.io.IOException If validation fails
+       */
+      void checkValidity(URL url, File file) throws IOException;
+   }
+}
\ No newline at end of file

LCGO/src/java/hep/lcgo/xml/reader
Constant.java added at 1.1
diff -N Constant.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Constant.java	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,46 @@
+package hep.lcgo.xml.reader;
+
+import org.jdom.DataConversionException;
+import org.jdom.Element;
+
+/**
+ * The class created when a constant definition is found in the XML file.
+ * @author tonyj
+ * @version $Id: Constant.java,v 1.1 2006/09/29 16:27:18 tonyj Exp $
+ */
+public class Constant
+{
+   private final String name;
+   private final double value;
+   /**
+    * Construct a new Constant
+    * @param constant The JDOM element corresponding to the constant definition.
+    * @throws org.jdom.DataConversionException If an XML error occurs while handling the node.
+    */
+   protected Constant(Element constant) throws DataConversionException
+   {
+      name = constant.getAttributeValue("name");
+      value = constant.getAttribute("value").getDoubleValue();
+   }
+   /**
+    * Get the name of this constant
+    * @return The name.
+    */
+   public String getName()
+   {
+      return name;
+   }
+   /**
+    * The value of this constant (after expression evaluation).
+    * @return The value.
+    */
+   public double getValue()
+   {
+      return value;
+   }
+   
+   public String toString()
+   {
+      return String.valueOf(value);
+   }
+}

LCGO/src/java/hep/lcgo/xml/reader
Detector.java added at 1.1
diff -N Detector.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Detector.java	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,75 @@
+package hep.lcgo.xml.reader;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.jdom.Element;
+
+/**
+ * Default class created to represent the parsed detector.
+ * @author tonyj
+ * @version $Id: Detector.java,v 1.1 2006/09/29 16:27:18 tonyj Exp $
+ */
+public class Detector
+{
+    private Header header;
+    private final Map/*<String,Constant>*/ constants = new HashMap/*<String,Constant>*/();
+    
+    
+    /**
+     * Called by the reader to create a new Detector
+     * @param element The JDOM element corresponding to the detector definition in the XML file.
+     */
+    protected Detector(Element element)
+    {
+
+    }
+    
+    /**
+     * Called by the reader to associate a header with this detector
+     * @param header The header.
+     */
+    protected void setHeader(Header header)
+    {
+        this.header = header;
+    }
+    /**
+     * Get the header associated with this detector.
+     * @return The header
+     */
+    public Header getHeader()
+    {
+        return header;
+    }
+    
+    /**
+     * Get the detector name from the header.
+     * @return the detector name
+     */
+    public String getDetectorName()
+    {
+        return getHeader().getDetectorName();
+    }
+    
+    /**
+     * Called by the reader to add a constant to this detector.
+     * @param c The constant to add.
+     */
+    protected void addConstant(Constant c)
+    {
+        constants.put(c.getName(),c);
+    }
+    /**
+     * Get the constants associated with this detector.
+     * @return A map of containing all of the constants, indexed by name.
+     */
+    public Map/*<String,Constant>*/ getConstants()
+    {
+        return constants;
+    }
+    
+    public String toString()
+    {
+       return "Detector: "+header.getDetectorName()+" version: "+header.getVersion();
+    }
+
+}
\ No newline at end of file

LCGO/src/java/hep/lcgo/xml/reader
Header.java added at 1.1
diff -N Header.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Header.java	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,110 @@
+package hep.lcgo.xml.reader;
+
+import org.jdom.Element;
+
+/**
+ * The header of the LCGO detector description.
+ *
+ * @author tonyj
+ */
+public class Header
+{
+   private String name;
+   private String title = "NONE";
+   private String author = "NONE";
+   private String version = "NONE";
+   private String url = "NONE";
+   private String comment = "NONE";
+   
+   protected Header(Element info)
+   {
+      if (info.getAttributeValue("name") != null)
+      {
+         name = info.getAttributeValue("name");
+      }
+      else
+      {
+         throw new RuntimeException("info element for this detector is missing the name attribute.");
+      }
+      
+      if (info.getChild("author") != null)
+      {
+         author = info.getAttributeValue("author");
+      }
+      
+      if (info.getChild("title") != null)
+      {
+         title = info.getAttributeValue("title");
+      }
+      
+      if (info.getAttribute("version") != null)
+      {
+         version = info.getAttributeValue("version");
+      }
+      
+      if (info.getAttribute("url") != null)
+      {
+         url = info.getAttributeValue("url");
+      }
+      
+      if (info.getChild("comment") != null)
+      {
+         comment = info.getChild("comment").getTextNormalize();
+      }
+   }
+   
+   /**
+    * Get the detector name.
+    *
+    * @return The name.
+    */
+   public String getDetectorName()
+   {
+      return name;
+   }
+   
+   /**
+    * Get the author of this detector description.
+    *
+    * @return The author.
+    */
+   public String getAuthor()
+   {
+      return author;
+   }
+   
+   /**
+    * Get the version of the detector.
+    *
+    * @return The version
+    */
+   public String getVersion()
+   {
+      return version;
+   }
+   
+   /**
+    * The URL providing more information about this detector.
+    *
+    * @return The URL.
+    */
+   public String getURL()
+   {
+      return url;
+   }
+   
+   /**
+    * A comment describing the detector
+    *
+    * @return The comment.
+    */
+   public String getComment()
+   {
+      return comment;
+   }
+   
+   public String getTitle()
+   {
+      return title;
+   }
+}
\ No newline at end of file

LCGO/src/java/hep/lcgo/xml/reader
LCGOElementFactory.java added at 1.1
diff -N LCGOElementFactory.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ LCGOElementFactory.java	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,20 @@
+package hep.lcgo.xml.reader;
+
+import hep.lcgo.xml.reader.util.DefaultElementFactory;
+
+/**
+ *
+ * @author jeremym
+ */
+public class LCGOElementFactory extends DefaultElementFactory
+{
+    
+    /** Creates a new instance of CompactElementFactory */
+    public LCGOElementFactory()
+    {
+        super();
+        register(Constant.class);
+        register(Detector.class);
+        register(Header.class);
+    }
+}

LCGO/src/java/hep/lcgo/xml/reader
LCGOReader.java added at 1.1
diff -N LCGOReader.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ LCGOReader.java	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,117 @@
+package hep.lcgo.xml.reader;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import hep.lcgo.xml.reader.util.CachingEntityResolver;
+import hep.lcgo.xml.reader.util.ElementFactory;
+import hep.lcgo.xml.reader.util.JDOMExpressionFactory;
+import hep.lcgo.xml.reader.util.ElementFactory.ElementCreationException;
+
+/**
+ * A tool for reading xml files containing LCGO detector descriptions.
+ *
+ * This class does not create subclass objects.  For example, CylindricalBarrelCalorimeter
+ * is inserted into Detector as a generic Subdetector.  To get subclasses, use the
+ * org.lcsim.geometry.GeometryReader class, which extends this.
+ *
+ * @author tonyj
+ * @version $Id: LCGOReader.java,v 1.1 2006/09/29 16:27:18 tonyj Exp $
+ *
+ */
+public class LCGOReader
+{
+    private ElementFactory factory;
+    
+    /**
+     * Create a CompactReader using a DefaultElementFactory.
+     */
+    public LCGOReader()
+    {
+        this(new LCGOElementFactory());
+    }
+    /**
+     * Create a CompactReader using the specified ElementFactory.
+     * @param factory The ElementFactory to be used for creating elements as the file is parsed.
+     */
+    public LCGOReader(ElementFactory factory)
+    {
+        this.factory = factory;
+    }
+    
+    public Detector read(String fileName) throws IOException, JDOMException, ElementCreationException
+    {
+        InputStream in = new FileInputStream(fileName);
+        try
+        {
+            return read(in);
+        }
+        finally
+        {
+            in.close();
+        }  
+    }
+    /**
+     * Read a compact geometry XML file.
+     * @param in The input stream to read.
+     * @throws java.io.IOException If an IO error occurs while reading the stream.
+     * @throws org.jdom.JDOMException If invalid XML is found while reading the file.
+     * @throws org.lcsim.geometry.compact.ElementFactory.ElementCreationException If the ElementFactory throws an ElementCreationException.
+     * @return The parsed detector description.
+     */
+    public Detector read(InputStream in) throws IOException, JDOMException, ElementCreationException
+    {
+        JDOMExpressionFactory jdom = new JDOMExpressionFactory();
+        SAXBuilder builder = new SAXBuilder("org.apache.xerces.parsers.SAXParser");
+        builder.setFactory(jdom);        
+        
+        builder.setValidation(true);
+        builder.setFeature("http://apache.org/xml/features/validation/schema", true);
+        
+        // Add an EntityResolver that caches to ~/.cache
+        builder.setEntityResolver(new CachingEntityResolver());
+       
+        Document doc = builder.build(in);
+        
+        Element lccdd = doc.getRootElement();
+        Detector det = (Detector) factory.createElement(Detector.class,lccdd,null);
+        
+        readHeader(lccdd, det, jdom);       
+        return det;
+    }
+    
+    private void readHeader(Element lccdd, Detector det, JDOMExpressionFactory jdom) throws JDOMException, ElementCreationException
+    {
+        Element info = lccdd.getChild("info");
+        det.setHeader((Header) factory.createElement(Header.class,info,null));
+        Element define = lccdd.getChild("define");
+        for (Iterator i = define.getChildren("constant").iterator(); i.hasNext(); )
+        {
+            Element constant = (Element) i.next();
+            Constant c = (Constant) factory.createElement(Constant.class,constant,null);
+            jdom.addConstant(c.getName(),c.getValue());
+            det.addConstant(c);
+        }
+    }
+    // Fixme: Should not be here
+    public static void main(String[] args) throws FileNotFoundException, IOException, JDOMException, ElementCreationException
+    {
+       LCGOReader reader = new LCGOReader();
+       Detector det = reader.read(new FileInputStream(args[0]));
+       Map constants = det.getConstants();
+       for (Iterator i = constants.entrySet().iterator(); i.hasNext(); )
+       {
+          Map.Entry entry = (Map.Entry) i.next();
+          Constant c = (Constant) entry.getValue();
+          System.out.println(entry.getKey()+"="+c.getValue());
+       }
+    }
+}

LCGO/src/java/hep/lcgo/xml/reader
package.html added at 1.1
diff -N package.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ package.html	29 Sep 2006 16:27:18 -0000	1.1
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+  <body>
+  A package for reading LCGO geometry XML files.
+  </body>
+</html>

LCGO/src/java/hep/lcgo/xml/reader/util
CachingEntityResolver.java added at 1.1
diff -N CachingEntityResolver.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CachingEntityResolver.java	29 Sep 2006 16:27:19 -0000	1.1
@@ -0,0 +1,38 @@
+package hep.lcgo.xml.reader.util;
+
+import hep.lcgo.util.cache.FileCache;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * An entity resolver which caches schemas locally. This makes it possible to run
+ * the tests without a network connection, provided the cache has been previously
+ * seeded.
+ * @author tonyj
+ * @version $Id: CachingEntityResolver.java,v 1.1 2006/09/29 16:27:19 tonyj Exp $
+ */
+public class CachingEntityResolver implements EntityResolver
+{
+   private final FileCache fileCache;
+   
+   public CachingEntityResolver() throws IOException
+   {
+      fileCache = new FileCache();
+   }
+   public CachingEntityResolver(File cacheDirectory) throws IOException
+   {
+      fileCache = new FileCache(cacheDirectory);
+   }
+   public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
+   {
+      File file = fileCache.getCachedFile(new URL(systemId));
+      InputSource result = new InputSource(new FileInputStream(file));
+      result.setSystemId(systemId);
+      return result;
+   }
+}
\ No newline at end of file

LCGO/src/java/hep/lcgo/xml/reader/util
DefaultElementFactory.java added at 1.1
diff -N DefaultElementFactory.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DefaultElementFactory.java	29 Sep 2006 16:27:19 -0000	1.1
@@ -0,0 +1,100 @@
+package hep.lcgo.xml.reader.util;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import hep.lcgo.xml.reader.util.ElementFactory.ElementCreationException;
+
+
+/**
+ * The default implementation of ElementFactory.
+ * @author tonyj
+ */
+public class DefaultElementFactory implements ElementFactory
+{
+   private List/*<Class>*/ classes = new ArrayList/*<Class>*/();
+   private Map/*<Class,String>*/ packageMap = new HashMap/*<Class,String>*/();
+   
+   /**
+    * Create the default element factory.
+    */
+   public DefaultElementFactory()
+   {}
+   
+   public Object /*<T> T*/ createElement(Class/*<T>*/ c, Element node, String type) throws JDOMException, ElementCreationException
+   {
+      if (type != null)
+      {
+         Class/*<T>*/ cand = getElementClass(c,type);
+         if (cand != null) return create(cand,node);
+      }
+      for (Iterator i = classes.iterator(); i.hasNext(); )
+      {
+         Class cand = (Class) i.next();
+         if (c.isAssignableFrom(cand)) return create(/*(Class<? extends T>)*/ cand,node);
+      }
+      throw new ElementCreationException("Unknown element "+c);
+   }
+   
+   public void register(Class elementClass,String packageName)
+   {
+      packageMap.put(elementClass,packageName);
+   }
+   /**
+    * Register a class with the factory. Future calls to create any class which is a subclass 
+    * of this class will cause a new instance of this class to be created. The class specificed
+    * must have a constructor which takes a jdom Element as its argument.
+    * @param elementClass The class to register.
+    */
+   public void register(Class elementClass)
+   {
+      classes.add(0,elementClass);
+   }
+   private Object/*<T> T*/ create(Class/*<T>*/ type, Element node) throws ElementCreationException
+   {
+      try
+      {
+         Constructor/*<T>*/ c = type.getDeclaredConstructor(new Class[]{Element.class});
+         c.setAccessible(true);
+         return c.newInstance(new Object[]{node});
+      }
+      catch (NoSuchMethodException x)
+      {
+         throw new ElementCreationException("Could not create element: "+type,x);
+      }
+      catch (InvocationTargetException x)
+      {
+         throw new ElementCreationException("Could not create element: "+type,x.getTargetException());
+      }
+      catch (InstantiationException x)
+      {
+         throw new ElementCreationException("Could not create element: "+type,x.getCause());
+      }
+      catch (IllegalAccessException x)
+      {
+         throw new ElementCreationException("Could not create element: "+type,x);
+      }
+   }
+   public Class/*<T> Class<T>*/ getElementClass(Class/*<T>*/ type, String name) throws ElementCreationException
+   {
+      String packageName = packageMap.get(type).toString();
+      if (packageName == null) return null;
+      String key = packageName+"."+name;
+      try
+      {
+         Class result = Class.forName(key);
+         if (!type.isAssignableFrom(result)) throw new ElementCreationException("Element "+key+" is of wrong type");
+         return /*(Class<T>)*/ result;
+      }
+      catch (ClassNotFoundException x)
+      {
+         return null;
+      }
+   }
+}
\ No newline at end of file

LCGO/src/java/hep/lcgo/xml/reader/util
ElementFactory.java added at 1.1
diff -N ElementFactory.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ElementFactory.java	29 Sep 2006 16:27:19 -0000	1.1
@@ -0,0 +1,28 @@
+package hep.lcgo.xml.reader.util;
+
+import org.jdom.Element;
+import org.jdom.JDOMException;
+
+/**
+ * An interface that must be implemented by all element factories.
+ * 
+ * By providing their own implementation of ElementFactory users can cause custom classes to be
+ * created by the reader.
+ * @author tonyj
+ * @version $Id: ElementFactory.java,v 1.1 2006/09/29 16:27:19 tonyj Exp $
+ */
+public interface ElementFactory
+{
+   Object /*<T> T*/ createElement(Class/*<T>*/ c, Element node, String type) throws JDOMException, ElementCreationException;
+   static class ElementCreationException extends Exception
+   {
+      ElementCreationException(String message)
+      {
+         super(message);
+      }
+      ElementCreationException(String message, Throwable cause)
+      {
+         super(message /*,cause*/);
+      }
+   }
+}
\ No newline at end of file

LCGO/src/java/hep/lcgo/xml/reader/util
JDOMExpressionFactory.java added at 1.1
diff -N JDOMExpressionFactory.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ JDOMExpressionFactory.java	29 Sep 2006 16:27:19 -0000	1.1
@@ -0,0 +1,161 @@
+package hep.lcgo.xml.reader.util;
+
+import gnu.jel.CompilationException;
+import gnu.jel.CompiledExpression;
+import gnu.jel.DVMap;
+import gnu.jel.Evaluator;
+import gnu.jel.Library;
+import java.util.HashMap;
+import java.util.Map;
+import org.jdom.Attribute;
+import org.jdom.DataConversionException;
+import org.jdom.DefaultJDOMFactory;
+import org.jdom.Namespace;
+
+/**
+ *
+ * @author tonyj
+ */
+public class JDOMExpressionFactory extends DefaultJDOMFactory
+{
+   private final Object[] resolver = { new Resolver() };
+   private final Library jelLibrary = setUpLibrary();
+   private final Map/*<String,Double>*/ constants = new HashMap/*<String,Double>*/();
+   
+   public void addConstant(String name, double value)
+   {
+      constants.put(name,new Double(value));
+   }
+   
+   public org.jdom.Attribute attribute(String name, String value, int type, Namespace namespace)
+   {
+      return new CustomAttribute(name,value,type,namespace);
+   }
+   
+   public org.jdom.Attribute attribute(String name, String value, Namespace namespace)
+   {
+      return new CustomAttribute(name,value,namespace);
+   }
+   
+   public org.jdom.Attribute attribute(String name, String value, int type)
+   {
+      return new CustomAttribute(name,value,type);
+   }
+   
+   public org.jdom.Attribute attribute(String name, String value)
+   {
+      return new CustomAttribute(name,value);
+   }
+   
+   private class CustomAttribute extends Attribute
+   {
+      CustomAttribute(String name, String value)
+      {
+         super(name,value);
+      }
+      CustomAttribute(String name, String value, int type)
+      {
+         super(name,value,type);
+      }
+      CustomAttribute(String name, String value, Namespace namespace)
+      {
+         super(name,value,namespace);
+      }
+      CustomAttribute(String name, String value, int type, Namespace namespace)
+      {
+         super(name,value,type,namespace);
+      }
+      
+      public long getLongValue() throws DataConversionException
+      {
+         String expression = super.getValue();
+         try
+         {
+            CompiledExpression expr = Evaluator.compile(expression,jelLibrary,Long.TYPE);
+            return expr.evaluate_long(resolver);
+         }
+         catch (Throwable x)
+         {
+            DataConversionException xx = new DataConversionException(expression,"long");
+            xx.initCause(x);
+            throw xx;
+         }
+      }
+      
+      public int getIntValue() throws DataConversionException
+      {
+         String expression = super.getValue();
+         try
+         {
+            CompiledExpression expr = Evaluator.compile(expression,jelLibrary,Integer.TYPE);
+            return expr.evaluate_int(resolver);
+         }
+         catch (Throwable x)
+         {
+            DataConversionException xx = new DataConversionException(expression,"int");
+            xx.initCause(x);
+            throw xx;
+         }
+      }
+      
+      public float getFloatValue() throws DataConversionException
+      {
+         String expression = super.getValue();
+         try
+         {
+            CompiledExpression expr = Evaluator.compile(expression,jelLibrary,Float.TYPE);
+            return expr.evaluate_float(resolver);
+         }
+         catch (Throwable x)
+         {
+            DataConversionException xx = new DataConversionException(expression,"float");
+            xx.initCause(x);
+            throw xx;
+         }
+      }
+      
+      public double getDoubleValue() throws DataConversionException
+      {
+         String expression = super.getValue();
+         try
+         {
+            CompiledExpression expr = Evaluator.compile(expression,jelLibrary,Double.TYPE);
+            return expr.evaluate_double(resolver);
+         }
+         catch (Throwable x)
+         {
+            DataConversionException xx = new DataConversionException(expression,"double");
+            xx.initCause(x);
+            throw xx;
+         }
+      }
+   }
+   private Library setUpLibrary()
+   {
+      try
+      {
+         Class[] staticLib = { Math.class };
+         Class[] dynamicLib = { Resolver.class };
+         Library lib = new Library(staticLib,dynamicLib,null,(Resolver) resolver[0],null);
+         lib.markStateDependent("random",null);
+         return lib;
+      }
+      catch (CompilationException x)
+      {
+         throw new RuntimeException(x); // should never happen
+      }
+   }
+   
+   public class Resolver extends DVMap
+   {
+      public String getTypeName(String str)
+      {
+         if (constants.containsKey(str)) return "Double";
+         return null;
+      }
+      public double getDoubleProperty(String str)
+      {
+         return ((Number) constants.get(str)).doubleValue();
+      }
+   }
+}
CVSspam 0.2.8