]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Partial application of the patch in Bugzilla 41044:
authorAndreas L. Delmelle <adelmelle@apache.org>
Sat, 7 Jul 2007 20:13:41 +0000 (20:13 +0000)
committerAndreas L. Delmelle <adelmelle@apache.org>
Sat, 7 Jul 2007 20:13:41 +0000 (20:13 +0000)
 * addition of a generic PropertyCache to be used by all Property
   types that can be safely canonicalized
 * modified EnumProperty, StringProperty, NumberProperty, EnumNumber
   and FixedLength to make use of the cache infrastructure

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@554251 13f79535-47bb-0310-9956-ffa450edef68

15 files changed:
src/java/org/apache/fop/fo/StaticPropertyList.java
src/java/org/apache/fop/fo/expr/CeilingFunction.java
src/java/org/apache/fop/fo/expr/FloorFunction.java
src/java/org/apache/fop/fo/expr/PropertyParser.java
src/java/org/apache/fop/fo/expr/RoundFunction.java
src/java/org/apache/fop/fo/properties/EnumNumber.java
src/java/org/apache/fop/fo/properties/EnumProperty.java
src/java/org/apache/fop/fo/properties/FixedLength.java
src/java/org/apache/fop/fo/properties/FontFamilyProperty.java
src/java/org/apache/fop/fo/properties/LengthProperty.java
src/java/org/apache/fop/fo/properties/NumberProperty.java
src/java/org/apache/fop/fo/properties/PropertyCache.java [new file with mode: 0644]
src/java/org/apache/fop/fo/properties/StringProperty.java
src/java/org/apache/fop/fo/properties/TableBorderPrecedence.java
status.xml

index 1ef3abd73c9480c648d5895e0083c11bb3637dce..de020126fba678d99186963ca835bef060e5f43b 100755 (executable)
@@ -24,8 +24,8 @@ import org.apache.fop.fo.properties.Property;
  * the explicit set properties and another array to store cached values.
  */
 public class StaticPropertyList extends PropertyList {
-    private Property[] explicit;
-    private Property[] values;
+    private final Property[] explicit;
+    private final Property[] values;
     
     /**
      * Construct a StaticPropertyList. 
index 9330fbdb36e7dceb35cf5a3f85e877da4a1d4940..29ac1940ae4a7af6cf5e9e97f091018a53462c27 100644 (file)
@@ -34,7 +34,7 @@ class CeilingFunction extends FunctionBase {
         if (dbl == null) {
             throw new PropertyException("Non number operand to ceiling function");
         }
-        return new NumberProperty(Math.ceil(dbl.doubleValue()));
+        return NumberProperty.getInstance(Math.ceil(dbl.doubleValue()));
     }
 
 }
index e7d253d692595288a1ac652305628df52bf82050..9cdbf1a2832d2ed1a18f55c4a68c1a130cd048c5 100644 (file)
@@ -35,7 +35,7 @@ class FloorFunction extends FunctionBase {
         if (dbl == null) {
             throw new PropertyException("Non number operand to floor function");
         }
-        return new NumberProperty(Math.floor(dbl.doubleValue()));
+        return NumberProperty.getInstance(Math.floor(dbl.doubleValue()));
     }
 
 }
index 5b5956f446476adb9ccec5e5029243b1cbef4b46..3bb15cc4ce96245066ebea2953d2cc7cb18de92e 100644 (file)
@@ -117,7 +117,7 @@ public final class PropertyParser extends PropertyTokenizer {
         next();
         if (currentToken == TOK_EOF) {
             // if prop value is empty string, force to StringProperty
-            return new StringProperty("");
+            return StringProperty.getInstance("");
         }
         ListProperty propList = null;
         while (true) {
@@ -245,7 +245,7 @@ public final class PropertyParser extends PropertyTokenizer {
             return prop;
 
         case TOK_LITERAL:
-            prop = new StringProperty(currentTokenValue);
+            prop = StringProperty.getInstance(currentTokenValue);
             break;
 
         case TOK_NCNAME:
@@ -254,11 +254,11 @@ public final class PropertyParser extends PropertyTokenizer {
             break;
 
         case TOK_FLOAT:
-            prop = new NumberProperty(new Double(currentTokenValue));
+            prop = NumberProperty.getInstance(new Double(currentTokenValue));
             break;
 
         case TOK_INTEGER:
-            prop = new NumberProperty(new Integer(currentTokenValue));
+            prop = NumberProperty.getInstance(new Integer(currentTokenValue));
             break;
 
         case TOK_PERCENT:
@@ -271,7 +271,7 @@ public final class PropertyParser extends PropertyTokenizer {
             PercentBase pcBase = this.propInfo.getPercentBase();
             if (pcBase != null) {
                 if (pcBase.getDimension() == 0) {
-                    prop = new NumberProperty(pcval * pcBase.getBaseValue());
+                    prop = NumberProperty.getInstance(pcval * pcBase.getBaseValue());
                 } else if (pcBase.getDimension() == 1) {
                     prop = new PercentLength(pcval, pcBase);
                 } else {
@@ -279,7 +279,7 @@ public final class PropertyParser extends PropertyTokenizer {
                 }
             } else {
                 // WARNING? Interpret as a decimal fraction, eg. 50% = .5
-                prop = new NumberProperty(pcval);
+                prop = NumberProperty.getInstance(pcval);
             }
             break;
 
@@ -290,10 +290,11 @@ public final class PropertyParser extends PropertyTokenizer {
             Double numPart = new Double(currentTokenValue.substring(0,
                     numLen));
             if (unitPart.equals(RELUNIT)) {
-                prop = (Property) NumericOp.multiply(new NumberProperty(numPart.doubleValue()),
+                prop = (Property) NumericOp.multiply(
+                                    NumberProperty.getInstance(numPart.doubleValue()),
                                     propInfo.currentFontSize());
             } else {
-                prop = new FixedLength(numPart.doubleValue(), unitPart);
+                prop = FixedLength.getInstance(numPart.doubleValue(), unitPart);
             }
             break;
 
@@ -365,7 +366,8 @@ public final class PropertyParser extends PropertyTokenizer {
             expectRpar();
         }
         if (i == nbArgs - 1 && function.padArgsWithPropertyName()) {
-            args[i++] = new StringProperty(propInfo.getPropertyMaker().getName());
+            args[i++] = StringProperty.getInstance(
+                            propInfo.getPropertyMaker().getName());
         }
         if (nbArgs != i) {
             throw new PropertyException("Expected " + nbArgs
@@ -521,7 +523,7 @@ public final class PropertyParser extends PropertyTokenizer {
         if (op1 == null || op2 == null) {
             throw new PropertyException("Non number operand to modulo");
         }
-        return new NumberProperty(op1.doubleValue() % op2.doubleValue());
+        return NumberProperty.getInstance(op1.doubleValue() % op2.doubleValue());
     }
 
 }
index f68f15e1688aae7515c29cb986c824377d2a4b72..a28a46e28fe5fcf95f6f9883ddcb3f75f8987d9f 100644 (file)
@@ -39,7 +39,7 @@ class RoundFunction extends FunctionBase {
         if (r == 0.0 && n < 0.0) {
             r = -r;    // round(-0.2) returns -0 not 0
         }
-        return new NumberProperty(r);
+        return NumberProperty.getInstance(r);
     }
 
 }
index a5679cbcc794b82ac70c62c8cf69a46cbc39d0bf..f8e940b0170a0689bcbf823daac757fe6b4fc476 100755 (executable)
  
 package org.apache.fop.fo.properties;
 
-import java.util.Map;
-import java.util.WeakHashMap;
-
 /**
  * A number quantity in XSL which is specified as an enum, such as "no-limit".
  */
 public class EnumNumber extends NumberProperty {
 
-    private static final Map cache = new WeakHashMap();
+    /** cache holding all canonical EnumNumber instances */
+    private static final PropertyCache cache = new PropertyCache();
 
     private final EnumProperty enumProperty;
     
-    private EnumNumber(EnumProperty enumProperty) {
+    /**
+     * Constructor
+     * @param enumProperty  the base EnumProperty
+     */
+    private EnumNumber(Property enumProperty) {
         super(null);
-        this.enumProperty = enumProperty;
+        this.enumProperty = (EnumProperty) enumProperty;
     }
 
+    /**
+     * Returns the canonical EnumNumber instance corresponding
+     * to the given Property
+     * @param enumProperty  the base EnumProperty
+     * @return  the canonical instance
+     */
     public static EnumNumber getInstance(Property enumProperty) {
-        EnumNumber en = (EnumNumber)cache.get(enumProperty);
-        if (en == null) {
-            en = new EnumNumber((EnumProperty)enumProperty);
-            cache.put(enumProperty, en);
-        }
-        return en;
+        return (EnumNumber)cache.fetch(
+                new EnumNumber((EnumProperty) enumProperty));
     }
 
     public int getEnum() {
@@ -81,5 +85,22 @@ public class EnumNumber extends NumberProperty {
         return enumProperty.getObject();
     }
 
+    /**
+     * @see java.lang.Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof EnumNumber) {
+            return (((EnumNumber)obj).enumProperty == this.enumProperty);
+        } else {
+            return false;
+        }
+    }
 
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return enumProperty.hashCode();
+    }
+    
 }
index 533ebd64f827e9013e319edf82b070973eba1627..f9801e22202270bd6a4073b7216db049b7cbc02a 100644 (file)
@@ -23,13 +23,13 @@ import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
 
-import java.util.Map;
-import java.util.WeakHashMap;
-
 /**
  * Superclass for properties that wrap an enumeration value
  */
 public class EnumProperty extends Property {
+    
+    /** cache holding all canonical EnumProperty instances */
+    private static final PropertyCache cache = new PropertyCache();
 
     /**
      * Inner class for creating EnumProperty instances
@@ -65,8 +65,6 @@ public class EnumProperty extends Property {
         }
     }
 
-    private static final Map propertyCache = new WeakHashMap();
-
     private final int value;
     private final String text;
 
@@ -80,14 +78,8 @@ public class EnumProperty extends Property {
     }
 
     public static EnumProperty getInstance(int explicitValue, String text) {
-        EnumProperty ep = new EnumProperty(explicitValue, text);
-        EnumProperty cacheEntry = (EnumProperty)propertyCache.get(ep);
-        if (cacheEntry == null) {
-            propertyCache.put(ep, ep);
-            return ep;
-        } else {
-            return cacheEntry;
-        }
+        return (EnumProperty) cache.fetch(
+                        new EnumProperty(explicitValue, text));
     }
 
     /**
@@ -119,6 +111,9 @@ public class EnumProperty extends Property {
         }
     }
 
+    /**
+     * @see java.lang.Object#hashCode()
+     */
     public int hashCode() {
         return value + text.hashCode();
     }
index a043d803ee1bb142d43c639ebcc5a1ed66136cd7..80016ba2e44c6de0617754acb3e32f7beb8a1b83 100644 (file)
@@ -25,26 +25,34 @@ import org.apache.fop.datatypes.PercentBaseContext;
  * An absolute length quantity in XSL
  */
 public class FixedLength extends LengthProperty {
+    
+    /** cache holding all canonical FixedLength instances */
+    private static final PropertyCache cache = new PropertyCache();
+    
     private int millipoints;
 
-    /**
-     * Set the length given
-     * @param numRelUnits the number of relative units
-     * @param iCurFontSize the current font size in base units.
-     */
-    public FixedLength(double numRelUnits, int iCurFontSize) {
-        millipoints = (int) (numRelUnits * (double)iCurFontSize);
-    }
-
     /**
      * Set the length given a number of units and a unit name.
      * @param numUnits quantity of input units
      * @param units input unit specifier (in, cm, etc.)
      */
-    public FixedLength(double numUnits, String units) {
+    private FixedLength(double numUnits, String units) {
         convert(numUnits, units);
     }
-
+    
+    /**
+     * Return the canonical FixedLength instance corresponding
+     * to the computed value
+     * @param numUnits  input units
+     * @param units     unit specifier
+     * @return
+     */
+    public static FixedLength getInstance(double numUnits, String units) {
+        return (FixedLength) cache.fetch(
+                    new FixedLength(numUnits, units));
+        
+    }
+    
     /**
      * @param baseUnits the length as a number of base units (millipoints)
      */
@@ -139,5 +147,22 @@ public class FixedLength extends LengthProperty {
         return millipoints + "mpt";
     }
 
+    /**
+     * @see java.lang.Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof EnumProperty) {
+            return (((FixedLength)obj).millipoints == this.millipoints);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return millipoints;
+    }
 }
 
index 62263a02c812f20df312e1262dd87d18da2c6a7f..58cbc64029f356f95d900b3bf3f0abb88362f7fd 100644 (file)
@@ -86,7 +86,7 @@ public class FontFamilyProperty extends ListProperty {
                                         + tmpVal.substring(dblSpaceIndex + 1);
                             dblSpaceIndex = tmpVal.indexOf("  ");
                         }
-                        prop.addProperty(new StringProperty(tmpVal));
+                        prop.addProperty(StringProperty.getInstance(tmpVal));
                     }
                 }
                 return prop;
index 79f9cfba73d051d98999262415b92ca3ecbee89b..8b5565e682bde73f5b48491972501f8b94be5938 100644 (file)
@@ -59,7 +59,7 @@ public abstract class LengthProperty extends Property
             }
             if (p instanceof NumberProperty) {
                 //Assume pixels (like in HTML) when there's no unit
-                return new FixedLength(p.getNumeric().getNumericValue(), "px");
+                return FixedLength.getInstance(p.getNumeric().getNumericValue(), "px");
             }
             Length val = p.getLength();
             if (val != null) {
index 21ffd32e7c8aa0dd4e34168ca6a1230d63be342e..55206cff7fd8ad64b234ac713767cd7ecd7e6c7f 100644 (file)
@@ -69,13 +69,16 @@ public class NumberProperty extends Property implements Numeric {
 
     }
 
-    private Number number;
+    /** cache holding all canonical NumberProperty instances */
+    private static final PropertyCache cache = new PropertyCache();
+    
+    private final Number number;
 
     /**
      * Constructor for Number input
      * @param num Number object value for property
      */
-    public NumberProperty(Number num) {
+    protected NumberProperty(Number num) {
         this.number = num;
     }
 
@@ -83,7 +86,7 @@ public class NumberProperty extends Property implements Numeric {
      * Constructor for double input
      * @param num double numeric value for property
      */
-    public NumberProperty(double num) {
+    protected NumberProperty(double num) {
         this.number = new Double(num);
     }
 
@@ -91,10 +94,43 @@ public class NumberProperty extends Property implements Numeric {
      * Constructor for integer input
      * @param num integer numeric value for property
      */
-    public NumberProperty(int num) {
+    protected NumberProperty(int num) {
         this.number = new Integer(num);
     }
     
+    /**
+     * Returns the canonical NumberProperty instance
+     * corresponding to the given Number
+     * @param num   the base Number
+     * @return  the canonical NumberProperty
+     */
+    public static NumberProperty getInstance(Number num) {
+        return (NumberProperty)cache.fetch(
+                    new NumberProperty(num));
+    }
+    
+    /**
+     * Returns the canonical NumberProperty instance
+     * corresponding to the given double
+     * @param num   the base double value
+     * @return  the canonical NumberProperty
+     */
+    public static NumberProperty getInstance(double num) {
+        return (NumberProperty)cache.fetch(
+                    new NumberProperty(num));
+    }
+
+    /**
+     * Returns the canonical NumberProperty instance
+     * corresponding to the given int
+     * @param num   the base int value
+     * @return  the canonical NumberProperty
+     */
+    public static NumberProperty getInstance(int num) {
+        return (NumberProperty)cache.fetch(
+                    new NumberProperty(num));
+    }
+    
     /**
      * Plain number always has a dimension of 0.
      * @return a dimension of 0.
@@ -172,7 +208,7 @@ public class NumberProperty extends Property implements Numeric {
     /** @see org.apache.fop.fo.properties.Property#getLength() */
     public Length getLength() {
         //Assume pixels (like in HTML) when there's no unit
-        return new FixedLength(getNumericValue(), "px");
+        return FixedLength.getInstance(getNumericValue(), "px");
     }
 
     /**
diff --git a/src/java/org/apache/fop/fo/properties/PropertyCache.java b/src/java/org/apache/fop/fo/properties/PropertyCache.java
new file mode 100644 (file)
index 0000000..176cdd4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.properties;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ *  Thin wrapper around a HashMap to implement the property caching idiom
+ *  in which a new Property instance is created then tested against cached
+ *  instances created previously. If an existing property is found, this is
+ *  retained and the newly created one is instantly eligible for garbage
+ *  collection.
+ */
+public class PropertyCache {
+
+    private Map propCache = Collections.synchronizedMap(new WeakHashMap());
+    
+    
+    /**
+     *  Checks if the given property is present in the cache - if so, returns
+     *  a reference to the cached value. Otherwise the given object is added
+     *  to the cache and returned.
+     *  @param obj
+     *  @return the cached instance
+     */
+    public Property fetch(Property prop) {
+        
+        Property cacheEntry = (Property) propCache.get(prop);
+        if (cacheEntry != null) {
+            return cacheEntry;
+        } else {
+            propCache.put(prop, prop);
+            return prop;
+        }
+    }
+}
index 1b1699c5a57f99d66b7c99210ca71ff3434adb9f..691942d788e34279565bc63520d8fdac0a4b40a6 100644 (file)
@@ -77,16 +77,30 @@ public class StringProperty extends Property {
 
     }    // end String.Maker
 
-    private String str;
+    /** cache containing all canonical StringProperty instances */
+    private static final PropertyCache cache = new PropertyCache();
+    
+    private final String str;
 
     /**
+     * Constructor
      * @param str String value to place in this object
      */
-    public StringProperty(String str) {
+    private StringProperty(String str) {
         this.str = str;
-        // log.debug("Set StringProperty: " + str);
     }
 
+    /**
+     * Return the canonical StringProperty instance 
+     * corresponding to the given string value
+     * @param str   the base String
+     * @return  the canonical instance
+     */
+    public static StringProperty getInstance(String str) {
+        return (StringProperty)cache.fetch(
+                   new StringProperty(str));
+    }
+    
     /**
      * @return the Object equivalent of this property
      */
@@ -101,4 +115,23 @@ public class StringProperty extends Property {
         return this.str;
     }
 
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof StringProperty) {
+            StringProperty sp = (StringProperty)obj;
+            return (sp.str == this.str
+                    || sp.str.equals(this.str));
+        } else {
+            return false;
+        }
+    }
+    
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return str.hashCode();
+    }
 }
index 9c094840efbcac5cd585b51ba91feede090c05ba..dff9626a162a704d3bd9f27c3272c103bde44d36 100644 (file)
@@ -25,13 +25,13 @@ import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
 
 public class TableBorderPrecedence extends NumberProperty.Maker{
-    private static Property num0 = new NumberProperty(0);
-    private static Property num1 = new NumberProperty(1);
-    private static Property num2 = new NumberProperty(2);
-    private static Property num3 = new NumberProperty(3);
-    private static Property num4 = new NumberProperty(4);
-    private static Property num5 = new NumberProperty(5);
-    private static Property num6 = new NumberProperty(6);
+    private static Property num0 = NumberProperty.getInstance(0);
+    private static Property num1 = NumberProperty.getInstance(1);
+    private static Property num2 = NumberProperty.getInstance(2);
+    private static Property num3 = NumberProperty.getInstance(3);
+    private static Property num4 = NumberProperty.getInstance(4);
+    private static Property num5 = NumberProperty.getInstance(5);
+    private static Property num6 = NumberProperty.getInstance(6);
 
     public TableBorderPrecedence(int propId) {
         super(propId);
index fdbf53fa162b77b779899bdc58e1b6b51dd9f91c..81d8e67512e69763b30173a0c4618fe7fa8eeebb 100644 (file)
 
   <changes>
     <release version="FOP Trunk">
+      <action context="code" dev="AD" type="add" fixes-bug="41044" due-to="Richard Wheeldon">
+        Partial application of the patch in Bugzilla 41044:
+          * addition of a generic PropertyCache to be used by all Property
+            types that can be safely canonicalized
+          * modified EnumProperty, StringProperty, NumberProperty, EnumNumber
+            and FixedLength to make use of the cache infrastructure
+      </action>
       <action context="code" dev="AD" type="update" fixes-bug="41656">
         Refactoring in the fo package:
         -> removal of the childNodes instance member in fop.fo.FObj