summaryrefslogtreecommitdiff
path: root/gnu/java
diff options
context:
space:
mode:
authorAndrew John Hughes <gnu_andrew@member.fsf.org>2006-01-10 15:59:36 +0000
committerAndrew John Hughes <gnu_andrew@member.fsf.org>2006-01-10 15:59:36 +0000
commite2880df85352a4f46c1fc8b28c4cd08540a2daed (patch)
treeaee81230bdbf73bd817662e0ce7a4665939ab41d /gnu/java
parent05f169147352fa3eeb9726f3d57597a83eb7d64d (diff)
downloadclasspath-e2880df85352a4f46c1fc8b28c4cd08540a2daed.tar.gz
2006-01-10 Andrew John Hughes <gnu_andrew@member.fsf.org>
Merge of HEAD --> generics branch for the period 2005/11/27 to 2006/01/09.
Diffstat (limited to 'gnu/java')
-rw-r--r--gnu/java/awt/peer/gtk/GdkGraphics.java91
-rw-r--r--gnu/java/awt/peer/gtk/GdkGraphics2D.java2
-rw-r--r--gnu/java/beans/encoder/ArrayPersistenceDelegate.java153
-rw-r--r--gnu/java/beans/encoder/ClassPersistenceDelegate.java80
-rw-r--r--gnu/java/beans/encoder/CollectionPersistenceDelegate.java84
-rw-r--r--gnu/java/beans/encoder/Context.java88
-rw-r--r--gnu/java/beans/encoder/GenericScannerState.java257
-rw-r--r--gnu/java/beans/encoder/IgnoringScannerState.java133
-rw-r--r--gnu/java/beans/encoder/MapPersistenceDelegate.java81
-rw-r--r--gnu/java/beans/encoder/ObjectId.java132
-rw-r--r--gnu/java/beans/encoder/PrimitivePersistenceDelegate.java74
-rw-r--r--gnu/java/beans/encoder/ReportingScannerState.java131
-rw-r--r--gnu/java/beans/encoder/Root.java198
-rw-r--r--gnu/java/beans/encoder/ScanEngine.java860
-rw-r--r--gnu/java/beans/encoder/ScannerState.java236
-rw-r--r--gnu/java/beans/encoder/StAXWriter.java233
-rw-r--r--gnu/java/beans/encoder/Writer.java174
-rw-r--r--gnu/java/beans/encoder/elements/ArrayInstantiation.java74
-rw-r--r--gnu/java/beans/encoder/elements/Array_Get.java62
-rw-r--r--gnu/java/beans/encoder/elements/Array_Set.java57
-rw-r--r--gnu/java/beans/encoder/elements/ClassResolution.java67
-rw-r--r--gnu/java/beans/encoder/elements/Element.java157
-rw-r--r--gnu/java/beans/encoder/elements/List_Get.java56
-rw-r--r--gnu/java/beans/encoder/elements/List_Set.java56
-rw-r--r--gnu/java/beans/encoder/elements/MethodInvocation.java62
-rw-r--r--gnu/java/beans/encoder/elements/NullObject.java61
-rw-r--r--gnu/java/beans/encoder/elements/ObjectInstantiation.java68
-rw-r--r--gnu/java/beans/encoder/elements/ObjectReference.java68
-rw-r--r--gnu/java/beans/encoder/elements/PrimitiveInstantiation.java69
-rw-r--r--gnu/java/beans/encoder/elements/StaticFieldAccess.java66
-rw-r--r--gnu/java/beans/encoder/elements/StaticMethodInvocation.java67
-rw-r--r--gnu/java/beans/encoder/elements/StringReference.java63
-rw-r--r--gnu/java/net/CRLFInputStream.java2
-rw-r--r--gnu/java/net/PlainDatagramSocketImpl.java133
-rw-r--r--gnu/java/net/PlainSocketImpl.java244
-rw-r--r--gnu/java/nio/DatagramChannelImpl.java2
-rw-r--r--gnu/java/nio/SelectorImpl.java26
-rw-r--r--gnu/java/nio/SocketChannelImpl.java2
-rw-r--r--gnu/java/nio/charset/Provider.java12
-rw-r--r--gnu/java/security/Engine.java11
-rw-r--r--gnu/java/util/WeakIdentityHashMap.java862
41 files changed, 5149 insertions, 205 deletions
diff --git a/gnu/java/awt/peer/gtk/GdkGraphics.java b/gnu/java/awt/peer/gtk/GdkGraphics.java
index 84fb1371e..d7217aa7a 100644
--- a/gnu/java/awt/peer/gtk/GdkGraphics.java
+++ b/gnu/java/awt/peer/gtk/GdkGraphics.java
@@ -50,7 +50,6 @@ import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.image.ImageObserver;
import java.text.AttributedCharacterIterator;
-import java.util.regex.*;
public class GdkGraphics extends Graphics
{
@@ -81,18 +80,23 @@ public class GdkGraphics extends Graphics
native void initStateUnlocked (GtkComponentPeer component);
native void initState (int width, int height);
native void initFromImage (GtkImage image);
- native void copyState (GdkGraphics g);
+ native void nativeCopyState (GdkGraphics g);
+
+ /**
+ * A cached instance that is used by {@link #create} in order to avoid
+ * massive allocation of graphics contexts.
+ */
+ GdkGraphics cached = null;
+
+ /**
+ * A link to the parent context. This is used in {@link #dispose} to put
+ * this graphics context into the cache.
+ */
+ GdkGraphics parent = null;
GdkGraphics (GdkGraphics g)
{
- color = g.color;
- xorColor = g.xorColor;
- font = g.font;
- if (font == null)
- font = new Font ("Dialog", Font.PLAIN, 12);
- clip = new Rectangle (g.clip);
- component = g.component;
-
+ parent = g;
copyState (g);
}
@@ -162,12 +166,54 @@ public class GdkGraphics extends Graphics
public native void copyArea(int x, int y, int width, int height,
int dx, int dy);
- public Graphics create ()
+ /**
+ * Creates a copy of this GdkGraphics instance. This implementation can
+ * reuse a cached instance to avoid massive instantiation of Graphics objects
+ * during painting.
+ *
+ * @return a copy of this graphics context
+ */
+ public Graphics create()
+ {
+ GdkGraphics copy = cached;
+ if (copy == null)
+ copy = new GdkGraphics(this);
+ else
+ {
+ copy.copyState(this);
+ cached = null;
+ }
+ return copy;
+ }
+
+ public native void nativeDispose();
+
+ /**
+ * Disposes this graphics object. This puts this graphics context into the
+ * cache of its parent graphics if there is one.
+ */
+ public void dispose()
{
- return new GdkGraphics (this);
+ if (parent != null)
+ {
+ parent.cached = this;
+ parent = null;
+ }
+ else
+ nativeDispose();
}
- public native void dispose();
+ /**
+ * This is called when this object gets finalized by the garbage collector.
+ * In addition to {@link Graphics#finalize()} this calls nativeDispose() to
+ * make sure the native resources are freed before the graphics context is
+ * thrown away.
+ */
+ public void finalize()
+ {
+ super.finalize();
+ nativeDispose();
+ }
public boolean drawImage (Image img, int x, int y,
Color bgcolor, ImageObserver observer)
@@ -418,4 +464,23 @@ public class GdkGraphics extends Graphics
translateNative (x, y);
}
+
+ /**
+ * Copies over the state of another GdkGraphics to this instance. This is
+ * used by the {@link #GdkGraphics(GdkGraphics)} constructor and the
+ * {@link #create()} method.
+ *
+ * @param g the GdkGraphics object to copy the state from
+ */
+ private void copyState(GdkGraphics g)
+ {
+ color = g.color;
+ xorColor = g.xorColor;
+ font = g.font;
+ if (font == null)
+ font = new Font ("Dialog", Font.PLAIN, 12);
+ clip = new Rectangle (g.clip);
+ component = g.component;
+ nativeCopyState(g);
+ }
}
diff --git a/gnu/java/awt/peer/gtk/GdkGraphics2D.java b/gnu/java/awt/peer/gtk/GdkGraphics2D.java
index c9ed30126..d07820a97 100644
--- a/gnu/java/awt/peer/gtk/GdkGraphics2D.java
+++ b/gnu/java/awt/peer/gtk/GdkGraphics2D.java
@@ -1088,6 +1088,8 @@ public class GdkGraphics2D extends Graphics2D
public void setBackground(Color c)
{
+ if (c == null)
+ c = Color.WHITE;
bg = c;
}
diff --git a/gnu/java/beans/encoder/ArrayPersistenceDelegate.java b/gnu/java/beans/encoder/ArrayPersistenceDelegate.java
new file mode 100644
index 000000000..12d757e2d
--- /dev/null
+++ b/gnu/java/beans/encoder/ArrayPersistenceDelegate.java
@@ -0,0 +1,153 @@
+/* ArrayPersistenceDelegate.java - A PersistenceDelegate that handles arrays.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+import java.beans.Statement;
+
+import java.lang.reflect.Array;
+import java.util.HashMap;
+
+public class ArrayPersistenceDelegate extends PersistenceDelegate
+{
+ private static final HashMap NULL_VALUES = new HashMap();
+
+ static
+ {
+ NULL_VALUES.put(Boolean.TYPE, Boolean.FALSE);
+ NULL_VALUES.put(Byte.TYPE, Byte.valueOf((byte) 0));
+ NULL_VALUES.put(Short.TYPE, Short.valueOf((short) 0));
+ NULL_VALUES.put(Integer.TYPE, Integer.valueOf(0));
+ NULL_VALUES.put(Long.TYPE, Long.valueOf(0));
+ NULL_VALUES.put(Float.TYPE, Float.valueOf(0.0f));
+ NULL_VALUES.put(Double.TYPE, Double.valueOf(0.0));
+ }
+
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ Class type = oldInstance.getClass().getComponentType();
+
+ // oldInstance is expected to be an array, then
+ // getClass().getComponentType() should lead
+ // to its component type.
+ assert (type != null);
+
+ // Not handling primitive types in a special way here
+ // causes that Class.forName("int") is built as an Expression
+ // later which would cause an exception if executed. A special
+ // handling to avoid the execution for primitive types can be
+ // java.beans.Encoder.writeExpression() .
+ return new Expression(
+ oldInstance,
+ Array.class,
+ "newInstance",
+ new Object[] {
+ type,
+ new Integer(Array.getLength(oldInstance)) });
+ }
+
+ protected void initialize(Class type, Object oldInstance, Object newInstance,
+ Encoder out)
+ {
+ int length = Array.getLength(oldInstance);
+
+ // Compares the array value against a prototypical
+ // null value of the array's component type in order to skip
+ // writing the default values of an array.
+
+ // Note: I have no idea why the persistence delegate for arrays writes
+ // an Expression that reads the value and then writes a Statement that sets
+ // the value. However it turned out that object arrays work better with the
+ // get-Expression and primitive array work fine with the set-Statement.
+
+ type = type.getComponentType();
+ if (type.isPrimitive())
+ {
+ Object nullValue = NULL_VALUES.get(type);
+
+ for (int i = 0; i < length; i++)
+ {
+ Object oldValue = Array.get(oldInstance, i);
+
+ if (!oldValue.equals(nullValue))
+ {
+ out.writeExpression(new Expression(Array.class, "get",
+ new Object[] { oldInstance,
+ Integer.valueOf(i),
+ }));
+
+ out.writeStatement(new Statement(Array.class, "set",
+ new Object[] {
+ oldInstance,
+ Integer.valueOf(i),
+ oldValue
+ }));
+ }
+ }
+
+ }
+ else
+ {
+
+ for (int i = 0; i < length; i++)
+ {
+ Object oldValue = Array.get(oldInstance, i);
+
+ if (oldValue != null)
+ {
+ out.writeExpression(new Expression(Array.class, "get",
+ new Object[] { oldInstance,
+ Integer.valueOf(i),
+ }));
+
+ out.writeStatement(new Statement(Array.class, "set",
+ new Object[] {
+ oldInstance,
+ Integer.valueOf(i),
+ oldValue
+ }));
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/gnu/java/beans/encoder/ClassPersistenceDelegate.java b/gnu/java/beans/encoder/ClassPersistenceDelegate.java
new file mode 100644
index 000000000..7b0656a5d
--- /dev/null
+++ b/gnu/java/beans/encoder/ClassPersistenceDelegate.java
@@ -0,0 +1,80 @@
+/* ClassPersistenceDelegate.java - A PersistenceDelegate for the Class type.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.beans.encoder;
+
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+
+/** <p>The <code>ClassPersistenceDelegate</code> creates
+ * <code>Expression</code> instances which denote class resolutions.</p>
+ *
+ * <p>The class resolution is always the last step when serializing a tree
+ * of objects. Due to the recursive nature of the algorithm we need a way
+ * to end the recursion. This is achieved by the implementation of this
+ * {@link instantiate} method. Arbitrary classes are described with a call
+ * to <code>Class.forName</code>. However for the <code>Class</code> class
+ * we call <code>getClass()</code> on a <code>String.class</code> instance.
+ * This in turn lead to the resolution of the String class which is always
+ * encoded as <code>"".getClass()</code>. Finally the <code>Encoder</code>
+ * treats strings in a special way so that the recursion ends here.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class ClassPersistenceDelegate extends PersistenceDelegate
+{
+
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ Class oldClass = (Class) oldInstance;
+
+ // Due to the special handling of String instances in the Encoder
+ // this Expression does not lead to further class resolutions.
+ if (oldClass == String.class)
+ return new Expression(oldClass, "", "getClass", null);
+
+ // This Expression will lead to the class resolution of String.class.
+ if (oldClass == Class.class)
+ return new Expression(oldClass, String.class, "getClass", null);
+
+ // This Expression will lead to the class resolution of Class.class.
+ return new Expression(oldClass, Class.class, "forName",
+ new Object[] { oldClass.getName() });
+ }
+
+}
diff --git a/gnu/java/beans/encoder/CollectionPersistenceDelegate.java b/gnu/java/beans/encoder/CollectionPersistenceDelegate.java
new file mode 100644
index 000000000..f1375d2ec
--- /dev/null
+++ b/gnu/java/beans/encoder/CollectionPersistenceDelegate.java
@@ -0,0 +1,84 @@
+/* CollectionPersistenceDelegate.java - A PersistenceDelegate for Collection subclasses.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.util.Collection;
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+import java.beans.Statement;
+
+import java.util.Iterator;
+
+/** <p>A <code>PersistenceDelegate</code> implementation that calls
+ * the no-argument constructor to create the Collection instance and
+ * uses an iterator to add all the objects it reaches through it.</p>
+ *
+ * <p>It is used for <code>Set</code> and <code>List</code>
+ * implementations.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class CollectionPersistenceDelegate extends PersistenceDelegate
+{
+
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ return new Expression(
+ oldInstance,
+ oldInstance.getClass(),
+ "new",
+ null);
+ }
+
+ protected void initialize(Class type, Object oldInstance, Object newInstance,
+ Encoder out)
+ {
+ Iterator ite = ((Collection) oldInstance).iterator();
+
+ while (ite.hasNext())
+ {
+ out.writeStatement(new Statement(oldInstance, "add",
+ new Object[] { ite.next() }));
+
+ }
+
+ }
+
+}
diff --git a/gnu/java/beans/encoder/Context.java b/gnu/java/beans/encoder/Context.java
new file mode 100644
index 000000000..9126d496f
--- /dev/null
+++ b/gnu/java/beans/encoder/Context.java
@@ -0,0 +1,88 @@
+/* Context.java -- Provides calling context information to ScannerStates.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+/** A <code>Contect</code> object describes the current state
+ * and the call number while processing the original object
+ * tree in the {@link ScanEngine}.
+ *
+ * <p>The class allows to distinguish the different calling states
+ * and is neccessary for the child element skipping feature of
+ * the {@link GenericScannerState}.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class Context
+{
+ private String state;
+
+ private int call;
+
+ Context(String newState, int newCall)
+ {
+ state = newState;
+ call = newCall;
+ }
+
+ public int hashCode()
+ {
+ int hc = 7;
+ hc = 31 * hc + state.hashCode();
+ hc = 31 * hc + call;
+
+ return hc;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof Context))
+ return false;
+
+ Context that = (Context) o;
+
+ return state.equals(that.state)
+ && call == that.call;
+ }
+
+ public String toString()
+ {
+ return "Context [state=" + state + ", call=" + call + "]";
+ }
+}
diff --git a/gnu/java/beans/encoder/GenericScannerState.java b/gnu/java/beans/encoder/GenericScannerState.java
new file mode 100644
index 000000000..3c3f8a3d2
--- /dev/null
+++ b/gnu/java/beans/encoder/GenericScannerState.java
@@ -0,0 +1,257 @@
+/* GenericScannerState.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.util.HashMap;
+
+import gnu.java.beans.encoder.elements.ArrayInstantiation;
+import gnu.java.beans.encoder.elements.Array_Get;
+import gnu.java.beans.encoder.elements.Array_Set;
+import gnu.java.beans.encoder.elements.ClassResolution;
+import gnu.java.beans.encoder.elements.Element;
+import gnu.java.beans.encoder.elements.List_Get;
+import gnu.java.beans.encoder.elements.List_Set;
+import gnu.java.beans.encoder.elements.MethodInvocation;
+import gnu.java.beans.encoder.elements.NullObject;
+import gnu.java.beans.encoder.elements.ObjectInstantiation;
+import gnu.java.beans.encoder.elements.ObjectReference;
+import gnu.java.beans.encoder.elements.PrimitiveInstantiation;
+import gnu.java.beans.encoder.elements.StaticFieldAccess;
+import gnu.java.beans.encoder.elements.StaticMethodInvocation;
+import gnu.java.beans.encoder.elements.StringReference;
+
+/**
+ * This class is a {@link ScannerState} implementation that creates
+ * suitable {@link gnu.java.beans.encoder.elements.Element} instances
+ * for each transition variant.
+ *
+ * <p>Furthermore it can optionally skip a certain number of child
+ * elements. The algorithm can cope with the fact that one
+ * <code>GenericScannerState</code> instance may be called at
+ * different levels of recursions.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+class GenericScannerState extends ScannerState
+{
+ private int skipElements, initialSkipElements;
+
+ final Root root;
+
+ HashMap skipValues;
+
+ GenericScannerState(Root newRoot)
+ {
+ root = newRoot;
+ }
+
+ GenericScannerState(Root root, int skipElements)
+ {
+ this(root);
+ this.skipElements = initialSkipElements = skipElements;
+
+ if (skipElements > 0)
+ skipValues = new HashMap();
+ }
+
+ protected void enterImpl(Context ctx)
+ {
+ if (skipValues != null)
+ {
+ Integer skip = (Integer) skipValues.get(ctx);
+
+ if (skip == null)
+ {
+ skip = Integer.valueOf(initialSkipElements);
+ skipValues.put(ctx, skip);
+ }
+
+ skipElements = skip.intValue();
+ }
+ }
+
+ void methodInvocation(String methodName)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new MethodInvocation(methodName));
+ }
+
+ void staticMethodInvocation(String className, String methodName)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new StaticMethodInvocation(className, methodName));
+ }
+
+ void staticFieldAccess(String className, String fieldName)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new StaticFieldAccess(className, fieldName));
+ }
+
+ void classResolution(String className)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new ClassResolution(className));
+ }
+
+ void objectInstantiation(String className, ObjectId objectId)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ Element elem = new ObjectInstantiation(className);
+ elem.initId(objectId);
+
+ root.addChild(elem);
+ }
+
+ void primitiveInstantiation(String primitiveName, String valueAsString)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new PrimitiveInstantiation(primitiveName, valueAsString));
+ }
+
+ void objectArrayInstantiation(String arrayClassName, String lengthAsString,
+ ObjectId objectId)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ Element elem = new ArrayInstantiation(arrayClassName, lengthAsString);
+ elem.initId(objectId);
+
+ root.addChild(elem);
+ }
+
+ void primitiveArrayInstantiation(String arrayClassName, String lengthAsString,
+ ObjectId objectId)
+ {
+ objectArrayInstantiation(arrayClassName, lengthAsString, objectId);
+ }
+
+ void arraySet(String indexAsString)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new Array_Set(indexAsString));
+ }
+
+ void arrayGet(String indexAsString)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new Array_Get(indexAsString));
+ }
+
+ void listGet()
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new List_Get());
+ }
+
+ void listSet()
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new List_Set());
+ }
+
+ void nullObject()
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new NullObject());
+ }
+
+ void stringReference(String string)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new StringReference(string));
+ }
+
+ void objectReference(ObjectId id)
+ {
+ if (skipValues != null && skipElements > 0)
+ return;
+
+ root.addChild(new ObjectReference(id));
+ }
+
+ void end()
+ {
+ if (skipValues != null)
+ {
+ if (skipElements > 0)
+ skipElements--;
+ else
+ {
+ // Finishes the Element we are constructing.
+ root.end();
+ }
+ skipValues.put(context(), Integer.valueOf(skipElements));
+ }
+ else
+ root.end();
+
+ }
+
+ void enter()
+ {
+
+ }
+
+}
diff --git a/gnu/java/beans/encoder/IgnoringScannerState.java b/gnu/java/beans/encoder/IgnoringScannerState.java
new file mode 100644
index 000000000..054f1f005
--- /dev/null
+++ b/gnu/java/beans/encoder/IgnoringScannerState.java
@@ -0,0 +1,133 @@
+/* IgnoringScannerState.java -- A ScannerState that does nothing.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+/** A special {@link ScannerState} implementation that ignores all child
+ * elements.
+ *
+ * <p>Consider the call hierarchy:
+ * <code>
+ * methodInvocation
+ * objectInstantiation
+ * classResolution*
+ * objectInstantiation
+ * classResolution
+ * </code>
+ * </p>
+ *
+ * <p>When the ignoring state is active one can filter the elements of
+ * one level. One has to set up the state machine that a transition
+ * via "class resolution" from a state that was reached via "object
+ * instantation" reaches an <code>IgnoringScannerState</code>.</p>
+ *
+ * <p>Setting the default successor of a <code>IgnoringScannerState</code>
+ * to itself causes all elements of the call hierarchy to be skipped
+ * until another state is reached by going back.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+class IgnoringScannerState extends ScannerState
+{
+
+ void methodInvocation(String methodName)
+ {
+ }
+
+ void staticMethodInvocation(String className, String methodName)
+ {
+ }
+
+ void staticFieldAccess(String className, String fieldName)
+ {
+ }
+
+ void classResolution(String className)
+ {
+ }
+
+ void objectInstantiation(String className, ObjectId objectId)
+ {
+ }
+
+ void primitiveInstantiation(String primitiveName, String valueAsString)
+ {
+ }
+
+ void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId)
+ {
+ }
+
+ void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId)
+ {
+ }
+
+ void arraySet(String indexAsString)
+ {
+ }
+
+ void arrayGet(String indexAsString)
+ {
+ }
+
+ void listGet()
+ {
+ }
+
+ void listSet()
+ {
+ }
+
+ void nullObject()
+ {
+ }
+
+ void stringReference(String string)
+ {
+ }
+
+ void objectReference(ObjectId id)
+ {
+ }
+
+ void end()
+ {
+ }
+
+}
diff --git a/gnu/java/beans/encoder/MapPersistenceDelegate.java b/gnu/java/beans/encoder/MapPersistenceDelegate.java
new file mode 100644
index 000000000..84cdce94d
--- /dev/null
+++ b/gnu/java/beans/encoder/MapPersistenceDelegate.java
@@ -0,0 +1,81 @@
+/* MapPersistenceDelegate.java -- A PersistenceDelegate for Map subclasses.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.util.Map;
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+import java.beans.Statement;
+
+import java.util.Iterator;
+
+/**
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class MapPersistenceDelegate extends PersistenceDelegate
+{
+
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ return new Expression(
+ oldInstance,
+ oldInstance.getClass(),
+ "new",
+ null);
+ }
+
+ protected void initialize(Class type, Object oldInstance, Object newInstance,
+ Encoder out)
+ {
+ Map map = (Map) oldInstance;
+ Iterator ite = map.keySet().iterator();
+
+ while (ite.hasNext())
+ {
+ Object key = ite.next();
+ out.writeStatement(new Statement(oldInstance, "put",
+ new Object[] { key, map.get(key) }));
+
+ }
+
+ }
+
+}
diff --git a/gnu/java/beans/encoder/ObjectId.java b/gnu/java/beans/encoder/ObjectId.java
new file mode 100644
index 000000000..eca5c3da4
--- /dev/null
+++ b/gnu/java/beans/encoder/ObjectId.java
@@ -0,0 +1,132 @@
+/* ObjectId.java -- Simple object identification mechanism for XML encoding.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.util.HashMap;
+
+/**
+ * <p>
+ * ObjectId provides an object identification mechanism which gives each object
+ * a name in the form <code>&lt;class&gt;&lt;Nameindex&gt;</code>.
+ * </p>
+ *
+ * <p>
+ * Each id can be in an unused state which means that only one instance of the
+ * object is in use and a special id is not needed. Certain {@link
+ * gnu.java.beans.encoder.elements.Element} subclasses use this feature to find
+ * out whether they write the "id" attribute or not.
+ * </p>
+ * <p>
+ * An <code>ObjectId</code> instance is typically given to multiple objects.
+ * The second user should then invoke the {@link #init} method to generate the
+ * identification string and bring the id in the 'used' state.
+ * </p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class ObjectId
+{
+ /**
+ * Stores the index an object of a specific type should be given.
+ */
+ private static HashMap nameIndices = new HashMap();
+
+ private String id;
+
+ private Class klass;
+
+ ObjectId(Class klass)
+ {
+ this.klass = klass;
+ }
+
+ public boolean isUnused()
+ {
+ return id == null;
+ }
+
+ public String toString()
+ {
+ return (id != null) ? id : "<unused id>";
+ }
+
+ /**
+ * <p>
+ * Generates a simple Id by concatenating a class name with a self-increasing
+ * number.
+ * </p>
+ */
+ public void init()
+ {
+ assert (klass != null);
+
+ if (id != null)
+ return;
+
+ Integer count = (Integer) nameIndices.get(klass);
+ if (count == null)
+ {
+ count = Integer.valueOf(0);
+ }
+
+ if (klass.isArray())
+ {
+ Class ct = klass.getComponentType();
+ if (ct == Boolean.TYPE)
+ id = "booleanArray" + count.intValue();
+ else if (ct == Byte.TYPE)
+ id = "byteArray" + count.intValue();
+ else if (ct == Short.TYPE)
+ id = "shortArray" + count.intValue();
+ else if (ct == Integer.TYPE)
+ id = "intArray" + count.intValue();
+ else if (ct == Long.TYPE)
+ id = "longArray" + count.intValue();
+ else if (ct == Float.TYPE)
+ id = "floatArray" + count.intValue();
+ else if (ct == Double.TYPE)
+ id = "doubleArray" + count.intValue();
+ }
+ else
+ id = klass.getName() + count.intValue();
+
+ nameIndices.put(klass, Integer.valueOf(count.intValue() + 1));
+ }
+
+}
diff --git a/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java b/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java
new file mode 100644
index 000000000..8cb3705b4
--- /dev/null
+++ b/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java
@@ -0,0 +1,74 @@
+/* PrimitivePersistenceDelegate.java
+ -- A PersistenceDelegate for primitive data types.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.beans.encoder;
+
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+
+/**
+ * A shared PersistenceDelegate implementation for all primitive types.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class PrimitivePersistenceDelegate extends PersistenceDelegate
+{
+
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ // The implementation relies on the fact that every primitive
+ // wrapper class has a constructor accepting a String argument.
+ // By using these constructors creating a primitive instance
+ // depends on the String class only.
+ return new Expression(oldInstance, oldInstance.getClass(), "new",
+ new Object[] { oldInstance.toString() });
+ }
+
+ protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out)
+ {
+ // This is a hack to make serializing primitive arrays work correctly.
+ // Instead of modifying an existing primitive instance to make it equal
+ // with another instance (which is not possible because primitives are
+ // immutable) we create a new instance. This is against the specification
+ // of the initialize method but make things work fine.
+ out.writeExpression(new Expression(oldInstance, oldInstance.getClass(), "new",
+ new Object[] { oldInstance.toString() }));
+ }
+
+}
diff --git a/gnu/java/beans/encoder/ReportingScannerState.java b/gnu/java/beans/encoder/ReportingScannerState.java
new file mode 100644
index 000000000..fb6e061ae
--- /dev/null
+++ b/gnu/java/beans/encoder/ReportingScannerState.java
@@ -0,0 +1,131 @@
+/* ReportingScannerState.java -- A state for debugging purposes.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+/**
+ * A <code>ScannerState</code> implementation that prints useful details
+ * about its arguments. Use it when the XML encoding does not work correctly
+ * and you want to find out how things relate to each other.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+class ReportingScannerState extends ScannerState
+{
+
+ void methodInvocation(String methodName)
+ {
+ System.out.println("methodInvocation: " + methodName + "()");
+ }
+
+ void staticMethodInvocation(String className, String methodName)
+ {
+ System.out.println("staticMethodInvocation: " + className + "." + methodName + "()");
+ }
+
+ void staticFieldAccess(String className, String fieldName)
+ {
+ System.out.println("staticFieldAccess: " + className + "." + fieldName);
+ }
+
+ void classResolution(String className)
+ {
+ System.out.println("classResolution: " + className);
+ }
+
+ void objectInstantiation(String className, ObjectId objectId)
+ {
+ System.out.println("objectInstantiation: " + className);
+ }
+
+ void primitiveInstantiation(String primitiveName, String valueAsString)
+ {
+ System.out.println("primitiveInstantiation: (" + primitiveName + ") " + valueAsString);
+ }
+
+ void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId)
+ {
+ System.out.println("objectArrayInstantiation: new " + arrayClassName + "[" + lengthAsString + "]");
+ }
+
+ void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId)
+ {
+ System.out.println("primitiveArrayInstantiation: new " + arrayClassName + "[" + lengthAsString + "]");
+ }
+
+ void arraySet(String indexAsString)
+ {
+ System.out.println("arraySet: " + indexAsString);
+ }
+
+ void arrayGet(String indexAsString)
+ {
+ System.out.println("arrayGet: " + indexAsString);
+ }
+
+ void listGet()
+ {
+ System.out.println("listGet");
+ }
+
+ void listSet()
+ {
+ System.out.println("listSet");
+ }
+
+ void nullObject()
+ {
+ System.out.println("nullObject");
+ }
+
+ void stringReference(String string)
+ {
+ System.out.println("stringReference: " + string);
+ }
+
+ void objectReference(ObjectId id)
+ {
+ System.out.println("objectReference: " + id);
+ }
+
+ void end()
+ {
+ System.out.println("-close");
+ }
+
+}
diff --git a/gnu/java/beans/encoder/Root.java b/gnu/java/beans/encoder/Root.java
new file mode 100644
index 000000000..f4eade193
--- /dev/null
+++ b/gnu/java/beans/encoder/Root.java
@@ -0,0 +1,198 @@
+/* Root.java -- The root of an object tree.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.beans.XMLEncoder;
+import java.util.Iterator;
+import java.util.Stack;
+
+import gnu.java.beans.encoder.elements.Element;
+
+/** <p><code>Root</code> provides a simple interface to a tree of
+ * objects.</p>
+ *
+ * <p>Using an instance of this class a logical representation of
+ * the real object tree that is serialized can be built. When the
+ * actual data should be written as XML <code>Root</code> and
+ * {@link gnu.java.beans.encoder.elements.Element} class can provide
+ * context information which is used to write the best fitting
+ * XML representation.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class Root
+{
+ private Stack parents = new Stack();
+
+ private Element rootElement, current;
+
+ private boolean started;
+
+ public Root()
+ {
+ rootElement = current = new RootElement();
+ }
+
+ /** <p>Adds another child element to the tree.</p>
+ *
+ * <p>The new element automatically becomes the current
+ * element.</p>
+ *
+ * @param elem The new child element.
+ */
+ public void addChild(Element elem)
+ {
+ current.addChild(elem);
+
+ parents.push(current);
+ current = elem;
+ }
+
+ /**
+ * <p>Marks that the end of the current element
+ * is reached and that no more childs are added to
+ * it.</p>
+ *
+ * <p>The behavior is to return to the nearest parent
+ * element.</p>
+ */
+ public void end()
+ {
+ current = (Element) parents.pop();
+ }
+
+ /**
+ * <p>Goes back to the nearest parent element but
+ * deletes the just created child.</p>
+ *
+ * <p>This is used if something went wrong while
+ * processing the child element's {@link java.beans.Expression}
+ * or {@link java.beans.Statement}.</p>
+ *
+ */
+ public void deleteLast()
+ {
+ current = (Element) parents.pop();
+
+ current.removeLast();
+ }
+
+ /**
+ * <p>Traverses the elements in the object tree
+ * and creates their XML representation in the output
+ * stream of the given {@link Writer}.</p>
+ *
+ * <p>Finally the <code>Writer</code> is flushed.</p>
+ *
+ * @param writer The Writer instance that generates the XML representation.
+ */
+ public void traverse(Writer writer)
+ {
+ if (!started)
+ {
+ writer.writePreamble();
+ rootElement.writeStart(writer);
+ }
+ started = true;
+
+ traverse(writer, rootElement.iterator());
+
+ rootElement.clear();
+
+ writer.flush();
+ }
+
+ /** Writes the closing element and closes the {@link Writer}
+ *
+ * @param writer The Writer instance that generates the XML representation.
+ */
+ public void close(Writer writer)
+ {
+ rootElement.writeEnd(writer);
+ writer.close();
+ }
+
+ /** Recursively traverses the object tree.
+ *
+ * @param writer The Writer instance that generates the XML representation.
+ * @param ite An Iterator returning Element instances.
+ */
+ private void traverse(Writer writer, Iterator ite)
+ {
+ while (ite.hasNext())
+ {
+ Element e = (Element) ite.next();
+ e.writeStart(writer);
+
+ traverse(writer, e.iterator());
+
+ e.writeEnd(writer);
+
+ e.clear();
+ }
+ }
+
+ /** <p>A special Element implementation that represents the
+ * encoder's context.</p>
+ *
+ * <p>This element is written only once per Writer.</p>
+ *
+ * <p>It is assumed that this element is never empty to simplify
+ * the implementation.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org);
+ *
+ */
+ static class RootElement extends Element
+ {
+ public void writeStart(Writer writer)
+ {
+ writer.write("java", new String[] { "version", "class" },
+ new String[] { System.getProperty("java.version"),
+ XMLEncoder.class.getName() }, false);
+ }
+
+ public void writeEnd(Writer writer)
+ {
+ writer.writeEnd(false);
+ }
+
+ }
+
+}
diff --git a/gnu/java/beans/encoder/ScanEngine.java b/gnu/java/beans/encoder/ScanEngine.java
new file mode 100644
index 000000000..edf07d760
--- /dev/null
+++ b/gnu/java/beans/encoder/ScanEngine.java
@@ -0,0 +1,860 @@
+/* ScanEngine.java
+ -- Scans the input and generates an object tree that can be written as XML.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.beans.Expression;
+import java.beans.Statement;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Stack;
+
+/** <p>The <code>ScanEngine</code> is the main class of the backend of the
+ * XML persistence algorithm. It scans {@link java.beans.Expression} and
+ * {@link java.beans.Statement} instances and some raw objects via the
+ * {@link #writeObject} method and feeds it to a state machine. The
+ * state machine then constructs and object tree which is finally
+ * written as XML by a {@link Writer} implementation.</p>
+ *
+ * <p>How does it work?</p>
+ * <p>The <code>ScanEngine</code> sits below the {@link java.beans.XMLEncoder}
+ * class and is called by it exclusively. The <code>XMLEncoder</code> sends
+ * interpretive data by invoking {@link #writeExpression}, {@link #writeStatement}
+ * and {@link #writeObject}. The invocations of <code>writeExpression</code> and
+ * <code>writeStatement</code> are usually nested into each other and provide
+ * more information then necessary to generate the XML representation.
+ * Furthermore the meaning of certain <code>Expressions</code> differs
+ * depending on the enclosing elements or the inner elements have to be
+ * simply discarded.</p>
+ *
+ * <p>To cope with this state dependant nature the <code>ScanEngine</code>
+ * contains a state machine which is programmed statically (no adjustments are
+ * needed, all <code>ScanEngine</code> engines use the same setup). The
+ * <code>ScanEngine</code>'s job is to decode the <code>Expression</code>s,
+ * <code>Statement</code>s and certain objects (namely <code>String</code>,
+ * <code>null</code> objects and instances which are repeatedly provided to
+ * the encoder) into 13 low-level (event) methods, which denote the meaning of the
+ * argument. For example an <code>Expression</code> can be an array
+ * instantiation which provokes a call to {@link arrayInstantiation} or
+ * it can be a class resolution leading to a call to {@link #classResolution}.
+ * For the state machione the 13 methods are the distinct way to transit
+ * from one state to another. Whenever the <code>ScanEngine</code> calls
+ * one of the event methods the current's state successor for that event
+ * is fetched from the state machine configuration, the successpr becomes
+ * the current state and then the event method is called in the new current
+ * state. The last step allows the state instance to do something meaningful
+ * to the object tree.</p>
+ *
+ * <p>The state machine knows the concept of returning to the previous
+ * state. This is done using a stack of states which is popped every
+ * time a call to <code>writeStatement</code>, <code>writeExpression</code>
+ * in the <code>XMLEncoder</code> ends by calling the {@link #end} method.
+ * Note that due to the inheritance relationship of <code>Encoder</code>
+ * and <code>XMLEncoder</code> it is impossible for the
+ * <code>ScanEngine</code> itself to decide when an expression or statement
+ * ended. This can only be done in case of {@link #writeObject} calls because
+ * they are not nested.</p>
+ *
+ * <p>When the XML persistence mechanism reaches an object twice (and more)
+ * it should generate an XML element using the "idref" attribute and add
+ * an "id" attribute to its first instantiation. This complicates things a bit
+ * because the first instantiation will always be part of the object tree
+ * as some {@link gnu.java.beans.encoder.elements.Element} subclass instance when the
+ * second and further objects accesses are written. Therefore the {@link ObjectId}
+ * class was introduced which is shared between all the object tree elements
+ * and has the notion of an "unused" state meaning that no identification
+ * is needed. The relationship between an object and its <code>ObjectId</code>
+ * instance is stored in the <code>ScanEngine</code> and gets cleared whenever
+ * the {@link #flush} method is called. This method also writes the currently
+ * built object tree and generates the XML representation.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class ScanEngine
+{
+
+ /** Change this to true to let the ScanEngine print state transition
+ * information.
+ */
+ boolean DEBUG = false;
+
+ /**
+ * Stores the scanner engine states as values and their names as keys.
+ */
+ HashMap states = new HashMap();
+
+ /**
+ * Stores former scanner state and makes it possible to come back to them.
+ */
+ Stack parents = new Stack();
+
+ /**
+ * The currently active scanner state.
+ */
+ ScannerState current;
+
+ /**
+ * The root of an object tree that is later written to XML.
+ */
+ Root root;
+
+ /**
+ * The Writer used to generate the XML output.
+ */
+ Writer writer;
+
+ /** Stores the relationship between objects and their {@link ObjectId} instance.
+ */
+ IdentityHashMap objects = new IdentityHashMap();
+
+ public ScanEngine(OutputStream os)
+ {
+ // TODO: Provide another Writer implementation (e.g. one that does not use
+ // the XML APIs at all).
+ writer = new StAXWriter(os);
+ root = new Root();
+
+ final ScannerState start = current = new GenericScannerState(root);;
+ ScannerState conf;
+
+ // Use the ReportingScannerState to debug serialization issues.
+ register(ScannerState.DEFAULT_STATE_NAME, new IgnoringScannerState());
+
+ register("start", start);
+
+ // Special dead-end state where all transitions are ignored.
+ register("ignoreAll", new IgnoringScannerState())
+ .setDefaultSuccessor("ignoreAll");
+
+ // Object reference, string reference, null object
+ start.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple");
+ start.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple");
+ start.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple");
+ register("simple", new GenericScannerState(root))
+ .setDefaultSuccessor("ignoreAll");
+
+ // Class resolution.
+ start.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0");
+ register("classRes0",
+ new GenericScannerState(root)).setDefaultSuccessor("ignoreAll");
+
+ // Object instantiation.
+ start.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION,
+ "newObj0");
+ conf = register("newObj0", new GenericScannerState(root));
+ conf.setDefaultSuccessor("ignoreAll");
+
+ // Simply use the start state to encode method invocations inside of
+ // objects.
+ conf.putSuccessor(ScannerState.TRANSITION_METHOD_INVOCATION, "start");
+
+ // Primitive instantiations.
+ start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION,
+ "newPrimitive0");
+ register("newPrimitive0",
+ new GenericScannerState(root)).setDefaultSuccessor("ignoreAll");
+
+ // Object arrays use the ARRAY_GET transition to create setting the
+ // array values.
+ start.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION,
+ "newObjectArray");
+ conf = register("newObjectArray", new GenericScannerState(root));
+ conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "newOArrayGet");
+ conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION,
+ "ignoreAll");
+
+ // Get here when a value is set in the array.
+ register("newOArrayGet",
+ conf = new GenericScannerState(root));
+
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION,
+ "newOArrayGet_ignoreFirstInteger");
+
+ // "newArrayGet_ignoreFirstInteger" is set up mostly identical like the "start"
+ // state. Otherwise things would not behave the same when done inside
+ // arrays.
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple");
+ conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple");
+ conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple");
+ conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0");
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "newObj0");
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION,
+ "newPrimitiveArray");
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION,
+ "newObjectArray");
+
+ conf = register("newOArrayGet_ignoreFirstInteger",
+ new GenericScannerState(root, 1));
+
+ // In non-int primitive arrays class resolutions can happen
+ // but they should be ignored.
+ conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll");
+
+ // Spurious object and string references occur when setting array
+ // elements. This suppresses them.
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION,
+ "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll");
+
+ conf.setDefaultSuccessor("start");
+
+ // Primitive arrays use the ARRAY_SET transition to create setting the
+ // array values. This turned out to be the only working solution.
+ // When primitive arrays were handled by ARRAY_GET the values in boolean
+ // arrays were always skipped.
+ start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION,
+ "newPrimitiveArray");
+ conf = register("newPrimitiveArray", new GenericScannerState(root));
+ conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "newPArraySet");
+ conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION,
+ "ignoreAll");
+
+ conf = register("newPArraySet", new GenericScannerState(root));
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION,
+ "newPArraySet_ignoreFirstInteger");
+
+ // Primitive arrays ignore all kinds of non-primitive object information.
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE,
+ "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ingoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION,
+ "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION,
+ "ignoreAll");
+
+ conf = register("newPArraySet_ignoreFirstInteger",
+ new GenericScannerState(root, 1));
+
+ // In non-int primitive arrays class resolutions can happen
+ // but they should be ignored.
+ conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll");
+
+ // Spurious object and string references occur when setting array
+ // elements. This suppresses them.
+ conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION,
+ "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll");
+ conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll");
+ conf.setDefaultSuccessor("start");
+
+ }
+
+ /** Registers a <code>ScannerState</code> under a certain name.
+ *
+ * @param name Name of the state
+ * @param state The <code>ScannerState</code> instance.
+ * @return The second argument.
+ */
+ private ScannerState register(String name, ScannerState state)
+ {
+ state.init(name);
+
+ states.put(name, state);
+
+ return state;
+ }
+
+ /** Generates or returns an id for the given object which can be activated
+ * later if the object is suitable.
+ *
+ * <p>Objects are unsuitable if they are an instance of a primitive wrapper
+ * or String.</p>
+ *
+ * @param value The object to retrieve an id for.
+ * @return The id for the object or <code>null</code>.
+ */
+ private ObjectId retrieveId(Object value)
+ {
+ Class valueClass = value.getClass();
+ ObjectId id = null;
+
+ // Although multiple accesses to Class objects are not handled
+ // through ids we generate one for them, too. This allows us to detect
+ // second time references to such objects in the writeObject method
+ // and handle them in a special way.
+ if (valueClass != String.class
+ && valueClass.getSuperclass() != Number.class
+ && valueClass != Boolean.class)
+ {
+ if ((id = (ObjectId) objects.get(value)) == null)
+ {
+ id = new ObjectId(valueClass);
+ objects.put(value, id);
+ }
+ }
+
+ return id;
+ }
+
+ /** Scans the argument and calls one of event methods. See
+ * the introduction of this class for details.
+ *
+ * @param expr The expression to serialize.
+ */
+ public void writeExpression(Expression expr)
+ {
+ String methodName = expr.getMethodName();
+ Object[] args = expr.getArguments();
+ Object target = expr.getTarget();
+ Object value = null;
+
+ try
+ {
+ value = expr.getValue();
+ }
+ catch (Exception e)
+ {
+ throw (InternalError)
+ new InternalError(
+ "The Expression's value should be available at this point.")
+ .initCause(e);
+ }
+
+ // TODO: What if the value is null?
+ ObjectId id;
+ Class valueClass = value.getClass();
+
+ if (target == Array.class)
+ {
+ if (methodName.equals("newInstance"))
+ {
+ id = retrieveId(value);
+
+ Class ct = (Class) args[0];
+
+ if (ct.isPrimitive() || ct == Boolean.class || ct == Byte.class
+ || ct == Short.class || ct == Integer.class || ct == Long.class
+ || ct == Float.class || ct == Double.class)
+ primitiveArrayInstantiation(ct.getName(),
+ args[1].toString(),
+ id);
+ else
+ objectArrayInstantiation(ct.getName(),
+ args[1].toString(),
+ id);
+
+ return;
+ }
+ else if (methodName.equals("get"))
+ {
+ arrayGet(args[1].toString());
+
+ // The encoder does not call the ScanEngine
+ // when an object is serialized that we already know.
+ // We test for this situation and insert the object reference
+ // manually.
+ // Since there is already a workaround for the Class class
+ // in writeObject we have to except it from this behavior.
+ id = (ObjectId) objects.get(value);
+ if (id != null && valueClass != Class.class)
+ {
+ objectReference(id);
+ end();
+ }
+
+ return;
+ }
+ else if (methodName.equals("set"))
+ {
+ arraySet(args[1].toString());
+ return;
+ }
+ }
+
+ id = retrieveId(value);
+
+ if (target instanceof Class)
+ {
+ if (methodName.equals("new"))
+ {
+ Class targetClass = (Class) target;
+
+ // All primitive types have short-hand forms for their
+ // constructors.
+ if (valueClass == Boolean.class)
+ primitiveInstantiation("boolean", args[0].toString());
+ else if (valueClass == Byte.class)
+ primitiveInstantiation("byte", args[0].toString());
+ else if (valueClass == Short.class)
+ primitiveInstantiation("short", args[0].toString());
+ else if (valueClass == Integer.class)
+ primitiveInstantiation("int", args[0].toString());
+ else if (valueClass == Long.class)
+ primitiveInstantiation("long", args[0].toString());
+ else if (valueClass == Float.class)
+ primitiveInstantiation("float", args[0].toString());
+ else if (valueClass == Double.class)
+ primitiveInstantiation("double", args[0].toString());
+ else
+ objectInstantiation(targetClass.getName(), id);
+
+ return;
+ }
+ else if (value instanceof Class)
+ {
+ String className = ((Class) value).getName();
+
+ // At this point we know that some *static* method will be called.
+
+ if (methodName.equals("forName"))
+ {
+ // However "Class.forName" represents class resolution and has a
+ // special syntax.
+ classResolution(className);
+ return;
+ }
+ else if (methodName.equals("getField"))
+ {
+ // The same goes for "Class.getField".
+ // Note: The name of the wanted field is given in
+ // the argument array.
+ staticFieldAccess(className, args[0].toString());
+ return;
+ }
+ else
+ {
+ // If nothing fits it is just a static method
+ // invocation which we decode as such.
+ staticMethodInvocation(className, methodName);
+ return;
+ }
+ }
+ }
+ else if (target instanceof List)
+ {
+ // Special behavior for indexed get and set method for list-style
+ // classes.
+ // The arguments are in the args array but we need them as subelements.
+ if (methodName.equals("get"))
+ {
+ listGet();
+ return;
+ }
+ else if (methodName.equals("set"))
+ {
+ listSet();
+ return;
+ }
+ }
+
+ // If nothing else could be used then this is a normal
+ // method invocation.
+ methodInvocation(methodName);
+ }
+
+ /**
+ * Ends the current state and returns to the last one.
+ */
+ public void end()
+ {
+ current.end();
+
+ if (DEBUG) System.err.print("back from " + current.getName());
+
+ ScannerState oldCurrent = current;
+ current = (ScannerState) parents.pop();
+
+ if (DEBUG) System.err.println(" to " + current.getName());
+ }
+
+ /**
+ * Returns to the last state and deletes the last element in the object tree.
+ */
+ public void revoke()
+ {
+ ScannerState oldCurrent = current;
+ current = (ScannerState) parents.pop();
+
+ root.deleteLast();
+ }
+
+ /** Scans the argument and calls one of event methods. See
+ * the introduction of this class for details.
+ *
+ * @param stmt The statement to serialize.
+ */
+ public void writeStatement(Statement stmt)
+ {
+ // This is a simplified version of writeExpression. Everything
+ // that would not create something that is embedded in a <void> tag
+ // is left out (instantiation, getters, ...).
+ // TODO: Is this the right thing to do?
+
+ String methodName = stmt.getMethodName();
+ Object target = stmt.getTarget();
+ Object[] args = stmt.getArguments();
+
+ if (target == Array.class && methodName.equals("set"))
+ {
+ arraySet(args[1].toString());
+ return;
+ }
+
+ if (target instanceof List)
+ {
+ if (methodName.equals("set"))
+ {
+ listSet();
+ return;
+ }
+ }
+
+ // If nothing else could be used then this is a normal
+ // method invocation.
+ methodInvocation(methodName);
+ }
+
+ /** Scans the argument and calls one of event methods. See
+ * the introduction of this class for details.
+ *
+ * @param o The object to serialize.
+ */
+ public boolean writeObject(Object o)
+ {
+ ObjectId id = null;
+
+ if (o == null)
+ {
+ // Handle null objects which have a special syntax.
+ nullObject();
+ end();
+ }
+ else if (o.getClass() == String.class)
+ {
+ // Handle strings which are treated extremely special
+ // in the encoder (they are never converted into a
+ // Expression).
+ stringReference((String) o);
+ end();
+ }
+ else if ((id = (ObjectId) objects.get(o)) != null)
+ {
+ // Multiple references to a Class object do not generate
+ // an object reference but we use the id to detect that
+ // situation.
+ if (o.getClass() == Class.class)
+ {
+ classResolution(((Class) o).getName());
+ end();
+ return false;
+ }
+
+ // If our object has a corresponding ObjectId instance
+ // then generate an objectReference. This will
+ // initialize the id (= brings it in the "used" state)
+ // when this is the first referal.
+ objectReference(id);
+ end();
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Writes the currently constructed object tree out as
+ * XML and clears the object to {@link ObjectId} relations.
+ */
+ public void flush()
+ {
+ // Make all references unreachable. That means we have to generate
+ // new object ids.
+ objects.clear();
+
+ root.traverse(writer);
+ }
+
+ /** Writes the final bits if the object tree and closes the stream
+ * afterwards.
+ */
+ public void close()
+ {
+ flush();
+ root.close(writer);
+ }
+
+ /**
+ * Does a transition from one state to another using the given event.
+ *
+ * <p>This involves saving the current state, retrieving it's
+ * successor and setting it as the current state.</p>
+ *
+ * @param transition One of {@link ScannerStates]'s transition constants.
+ */
+ private void transition(int transition)
+ {
+ parents.push(current);
+
+ String stateName = current.getSuccessor(transition);
+
+ if (DEBUG)
+ {
+ System.err.println("from state: " + current.getName() + "\n\troute: "
+ + ScannerState.transitionNames[transition]
+ + "\n\t\tto state: "
+ + stateName);
+ }
+
+ ScannerState newState = (ScannerState) states.get(stateName);
+
+ newState.enter(new Context(current.getName(), current.getCalls()));
+
+ assert (newState != null) : "State '" + stateName + "' was not defined.";
+
+ current = newState;
+ }
+
+ /** Event method that denotes a (non-static) method invocation.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param methodName The name of the method which is called.
+ */
+ void methodInvocation(String methodName)
+ {
+ transition(ScannerState.TRANSITION_METHOD_INVOCATION);
+
+ current.methodInvocation(methodName);
+ }
+
+ /** Event method that denotes a static method invocation.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param methodName The name of the method which is called.
+ * @param className The name of the class in which the method is called.
+ */
+ void staticMethodInvocation(String className, String methodName)
+ {
+ transition(ScannerState.TRANSITION_STATIC_METHOD_INVOCATION);
+
+ current.staticMethodInvocation(className, methodName);
+ }
+
+ /** Event method that denotes the retrieval of a static field's value.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param fieldName The name of the field whose value is retrieved.
+ * @param className The name of the class in which the method is called.
+ */
+ void staticFieldAccess(String className, String fieldName)
+ {
+ transition(ScannerState.TRANSITION_STATIC_FIELD_ACCESS);
+
+ current.staticFieldAccess(className, fieldName);
+ }
+
+ /** Event method that denotes the resolution of a class.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param className The name of the class in which the method is called.
+ */
+ void classResolution(String className)
+ {
+ transition(ScannerState.TRANSITION_CLASS_RESOLUTION);
+
+ current.classResolution(className);
+ }
+
+ /** Event method that denotes the instantiation of an object.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param className The name of the class in which the method is called.
+ * @param objectId An ObjectId instance which can be activated later.
+ */
+ void objectInstantiation(String className, ObjectId objectId)
+ {
+ transition(ScannerState.TRANSITION_OBJECT_INSTANTIATION);
+
+ current.objectInstantiation(className, objectId);
+ }
+
+ /** Event method that denotes the instantiation of a primitive.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param primitiveName One of "boolean, "byte", "short", "int", "long"
+ * , "float" or "double"
+ * @param valueAsString The value of the primitive as a String.
+ */
+ void primitiveInstantiation(String primitiveName, String valueAsString)
+ {
+ transition(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION);
+
+ current.primitiveInstantiation(primitiveName, valueAsString);
+ }
+
+ /** Event method that denotes the instantiation of an object array.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param arrayClassName The array's class name.
+ * @param objectId An ObjectId instance which can be activated later.
+ * @param lengthAsString The array's length as String.
+ */
+ void objectArrayInstantiation(String arrayClassName, String lengthAsString,
+ ObjectId objectId)
+ {
+ transition(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION);
+
+ current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId);
+ }
+
+ /** Event method that denotes the instantiation of a primitive array.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param arrayClassName The array's class name.
+ * @param objectId An ObjectId instance which can be activated later.
+ * @param lengthAsString The array's length as String.
+ */
+ void primitiveArrayInstantiation(String arrayClassName, String lengthAsString,
+ ObjectId objectId)
+ {
+ transition(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION);
+
+ current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId);
+ }
+
+ /** Event method that denotes the setting of a value in an array.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param indexAsString The index to as a String.
+ */
+ void arraySet(String indexAsString)
+ {
+ transition(ScannerState.TRANSITION_ARRAY_SET);
+
+ current.arraySet(indexAsString);
+ }
+
+ /** Event method that denotes the retrieval of a value in an array.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @param indexAsString The index to as a String.
+ */
+ void arrayGet(String indexAsString)
+ {
+ transition(ScannerState.TRANSITION_ARRAY_GET);
+
+ current.arrayGet(indexAsString);
+ }
+
+ /** Event method that denotes the setting of a value in a list.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ */
+ void listSet()
+ {
+ transition(ScannerState.TRANSITION_LIST_SET);
+
+ current.listSet();
+ }
+
+ /** Event method that denotes the retrieval of a value in a list.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ */
+ void listGet()
+ {
+ transition(ScannerState.TRANSITION_LIST_GET);
+
+ current.listGet();
+ }
+
+ /** Event method that denotes the null value.
+ */
+ void nullObject()
+ {
+ transition(ScannerState.TRANSITION_NULL_OBJECT);
+
+ current.nullObject();
+ }
+
+ /** Event method that denotes a string.
+ *
+ * @param string The string that should be written.
+ */
+ void stringReference(String string)
+ {
+ transition(ScannerState.TRANSITION_STRING_REFERENCE);
+
+ current.stringReference(string);
+ }
+
+ /** Event method that denotes a reference to an existing object.
+ *
+ * @param id The ObjectId to be used.
+ */
+ void objectReference(ObjectId id)
+ {
+ transition(ScannerState.TRANSITION_OBJECT_REFERENCE);
+
+ current.objectReference(id);
+ }
+
+}
diff --git a/gnu/java/beans/encoder/ScannerState.java b/gnu/java/beans/encoder/ScannerState.java
new file mode 100644
index 000000000..888478a8e
--- /dev/null
+++ b/gnu/java/beans/encoder/ScannerState.java
@@ -0,0 +1,236 @@
+/* ScannerState.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.util.HashMap;
+
+/** <p>Provides the infrastructure for the state machine and the transition
+ * mechanism.</p>
+ *
+ * <p>Each states knows a set of successor. There can be one successor for
+ * every transition variant. Furthermore a state knows about a default
+ * successor which is taken when there is no special setup for a
+ * transition.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public abstract class ScannerState
+{
+
+ static final int TRANSITION_METHOD_INVOCATION = 0;
+
+ static final int TRANSITION_STATIC_METHOD_INVOCATION = 1;
+
+ static final int TRANSITION_STATIC_FIELD_ACCESS = 2;
+
+ static final int TRANSITION_CLASS_RESOLUTION = 3;
+
+ static final int TRANSITION_OBJECT_INSTANTIATION = 4;
+
+ static final int TRANSITION_PRIMITIVE_INSTANTIATION = 5;
+
+ static final int TRANSITION_OBJECT_ARRAY_INSTANTIATION = 6;
+
+ static final int TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION = 7;
+
+ static final int TRANSITION_ARRAY_SET = 8;
+
+ static final int TRANSITION_ARRAY_GET = 9;
+
+ static final int TRANSITION_LIST_SET = 10;
+
+ static final int TRANSITION_LIST_GET = 11;
+
+ static final int TRANSITION_NULL_OBJECT = 12;
+
+ static final int TRANSITION_STRING_REFERENCE = 13;
+
+ static final int TRANSITION_OBJECT_REFERENCE = 14;
+
+ static final int TRANSITION_FIRST = 0;
+
+ static final int TRANSITION_LAST = 14;
+
+ static final String DEFAULT_STATE_NAME = "default";
+
+ String defaultSuccessor = DEFAULT_STATE_NAME;
+
+ static String[] transitionNames = { "METHOD_INVOCATION", "STATIC_METHOD_INVOCATION",
+ "STATIC_FIELD_ACCESS", "CLASS_RESOLUTION",
+ "OBJECT_INSTANTIATION",
+ "PRIMITIVE_INSTANTIATION", "OBJECT_ARRAY_INSTANTIATION",
+ "PRIMITIVE_ARRAY_INSTANTIATION",
+ "ARRAY_SET", "ARRAY_GET", "LIST_SET", "LIST_GET",
+ "NULL_OBJECT", "STRING_REFERENCE", "OBJECT_REFERENCE" };
+
+ /**
+ * Stores the transition setup as the relation
+ * transition->successor's state name.
+ */
+ HashMap transitions = new HashMap();
+
+ int calls;
+
+ Context context;
+
+ String name;
+
+ final void init(String newName)
+ {
+ assert (name == null);
+
+ name = newName;
+ }
+
+ final String getName()
+ {
+ return name;
+ }
+
+ final void enter(Context ctx)
+ {
+ calls++;
+ context = ctx;
+
+ enterImpl(ctx);
+ }
+
+ protected void enterImpl(Context ctx)
+ {
+ }
+
+ final Context context()
+ {
+ return context;
+ }
+
+ final int getCalls()
+ {
+ return calls;
+ }
+
+ /**
+ * <p>Stores a successor's state name for a certain transition.</p>
+ *
+ * <p>This method is only used at the configuration time of the state
+ * machine.</p>
+ *
+ * @param transition One of the transition constants.
+ * @param stateName The state name of the successor.
+ */
+ final void putSuccessor(int transition, String stateName)
+ {
+ assert (transition >= TRANSITION_FIRST && transition <= TRANSITION_LAST) :
+ "Transition identifier '" + transition + "' is unknown.";
+
+ transitions.put(new Integer(transition), stateName);
+ }
+
+ /** <p>Retrieves a the state name of a successor for the given transition
+ * constant.</p>
+ *
+ * <p>Returns the default successor's state name if no special setup was
+ * prepared.</p>
+ *
+ * @param transition One of the transition constants.
+ * @return The state name of the successor.
+ */
+ final String getSuccessor(int transition)
+ {
+ String state = (String) transitions.get(new Integer(transition));
+
+ return (state == null) ? defaultSuccessor : state;
+ }
+
+ /**
+ * Sets the name for the default successor state.
+ *
+ * @param newDefaultSuccessor The default successor's state name.
+ */
+ final void setDefaultSuccessor(String newDefaultSuccessor)
+ {
+ defaultSuccessor = newDefaultSuccessor;
+ }
+
+ abstract void methodInvocation(String methodName);
+
+ abstract void staticMethodInvocation(String className, String methodName);
+
+ abstract void staticFieldAccess(String className, String fieldName);
+
+ abstract void classResolution(String className);
+
+ abstract void objectInstantiation(String className, ObjectId objectId);
+
+ abstract void primitiveInstantiation(String primitiveName,
+ String valueAsString);
+
+ abstract void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId);
+
+ abstract void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId);
+
+ abstract void arraySet(String indexAsString);
+
+ abstract void arrayGet(String indexAsString);
+
+ abstract void listGet();
+
+ abstract void listSet();
+
+ abstract void nullObject();
+
+ abstract void stringReference(String string);
+
+ abstract void objectReference(ObjectId id);
+
+ /**
+ * <p>A special event that does not provoke a direct transition.</p>
+ *
+ * <p>Instead the transition is done by the <code>ScanEngine</code>: It goes
+ * back to the previous state and just uses this method to inform the state
+ * about this happening.</p>
+ */
+ abstract void end();
+
+ void enter()
+ {
+ }
+
+}
diff --git a/gnu/java/beans/encoder/StAXWriter.java b/gnu/java/beans/encoder/StAXWriter.java
new file mode 100644
index 000000000..fdb5f7d45
--- /dev/null
+++ b/gnu/java/beans/encoder/StAXWriter.java
@@ -0,0 +1,233 @@
+/* StAXWriter.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.io.OutputStream;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+/** A {@link Writer} implementation based on the StAX API.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class StAXWriter implements Writer
+{
+ XMLStreamWriter writer;
+
+ int indent = 0;
+
+ public StAXWriter(OutputStream os)
+ {
+ try
+ {
+ XMLOutputFactory factory = XMLOutputFactory.newInstance();
+ writer = factory.createXMLStreamWriter(os);
+ }
+ catch (XMLStreamException se)
+ {
+ throw (InternalError)
+ new InternalError(
+ "Could not instantiate a streaming XML writer.")
+ .initCause(se);
+ }
+
+ }
+
+ public void flush()
+ {
+ if (writer != null)
+ {
+ try
+ {
+ writer.flush();
+ }
+ catch (XMLStreamException xse)
+ {
+ // TODO: find out
+ }
+ }
+
+ }
+
+ public void close()
+ {
+ if (writer != null)
+ {
+ try
+ {
+ writer.close();
+ }
+ catch (XMLStreamException xse)
+ {
+ // TODO: find out
+ }
+ writer = null;
+ }
+
+ }
+
+ public void writePreamble()
+ {
+ try
+ {
+ writer.writeStartDocument("UTF-8", "1.0");
+ }
+ catch (XMLStreamException xmlse)
+ {
+
+ }
+ }
+
+ public void writeEnd(boolean wasEmpty)
+ {
+ try
+ {
+ indent -= 2;
+
+ if (wasEmpty)
+ return;
+
+ for (int i = 0; i < indent; i++)
+ writer.writeCharacters(" ");
+
+ writer.writeEndElement();
+
+ writer.writeCharacters("\n");
+ }
+ catch (XMLStreamException xmlse)
+ {
+
+ }
+ }
+
+ public void writeEndNoChildren()
+ {
+ try
+ {
+ writer.writeEndElement();
+ writer.writeCharacters("\n");
+ }
+ catch (XMLStreamException xmlse)
+ {
+
+ }
+ }
+
+ public void write(String tagName, boolean empty)
+ {
+ write(tagName, null, null, null, empty);
+ }
+
+ public void write(String tagName, String value)
+ {
+ write(tagName, value, null, null, value == null);
+ }
+
+ public void writeNoChildren(String tagName, String value)
+ {
+ try
+ {
+ for (int i = 0; i < indent; i++)
+ writer.writeCharacters(" ");
+
+ writer.writeStartElement(tagName);
+
+ writer.writeCharacters(value);
+ }
+ catch (XMLStreamException xmlse)
+ {
+
+ }
+ }
+
+ public void write(String tagName, String attributeName,
+ String attributeValue, boolean empty)
+ {
+ write(tagName, null, new String[] { attributeName },
+ new String[] { attributeValue }, empty);
+ }
+
+ public void write(String tagName, String value, String[] attributeNames,
+ String[] attributeValues, boolean empty)
+ {
+ try
+ {
+ for (int i = 0; i < indent; i++)
+
+ writer.writeCharacters(" ");
+
+ if (empty)
+ writer.writeEmptyElement(tagName);
+ else
+ writer.writeStartElement(tagName);
+
+ if (attributeNames != null)
+ for (int i = 0; i < attributeNames.length; i++)
+ writer.writeAttribute(attributeNames[i], attributeValues[i]);
+
+ writer.writeCharacters("\n");
+
+ indent += 2;
+
+ if (value != null)
+ {
+ for (int i = 0; i < indent; i++)
+ writer.writeCharacters(" ");
+
+ writer.writeCharacters(value);
+
+ writer.writeCharacters("\n");
+ }
+ }
+ catch (XMLStreamException xmlse)
+ {
+
+ }
+ }
+
+ public void write(String tagName, String[] attributeNames,
+ String[] attributeValues, boolean empty)
+ {
+ write(tagName, null, attributeNames, attributeValues, empty);
+ }
+
+}
diff --git a/gnu/java/beans/encoder/Writer.java b/gnu/java/beans/encoder/Writer.java
new file mode 100644
index 000000000..57203d23e
--- /dev/null
+++ b/gnu/java/beans/encoder/Writer.java
@@ -0,0 +1,174 @@
+/* Writer.java -- Writing interface for XML persistence.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+/** A <code>Writer</code> represents a simplified interface to an XML
+ * writer that is used for the XML persistence mechanism.
+ *
+ * <p>Its sole purpose is to allow multiple backends which may remove
+ * the need to have certain APIs in the classpath. Eg. it is possible
+ * to write a stripped down XML Writer that does not rely on SAX, StAX
+ * or DOM APIs.</p>
+ *
+ * <p>The caller may assume that every action is done immediately. However
+ * it is possible that the underlying implementation uses buffering streams.
+ * To make sure the data is written call the {@link flush} method.</p>
+ *
+ * <p>The <code>Writer</code> implementation should care about the formatting
+ * of the XML stream making it possible to generate three types of formats using
+ * a special method invocation chain.</p>
+ *
+ * <p>Write
+ * <code>
+ * &lt;element/&gt;
+ * </code>
+ * by issuing <code>write("element", true)</code> (or any of the other
+ * write-variants that allows specifying the <code>isEmpty</code> argument)
+ * and <code>writeEnd(true)</code>.</p>
+ *
+ * <p>Write
+ * <code>
+ * &lt;element&gt;body&lt;/element&gt;
+ * </code>
+ * by issuing <code>writeNoChildren("element", "body")</code> and <code>writeNoChildrenEnd()</code>.</p>
+ *
+ * <p>
+ * Write
+ * <code>
+ * &lt;element&gt;
+ * &lt;child1/&gt;
+ * &lt;child2/&gt;
+ * ...
+ * &lt;element/&gt;
+ * </code>
+ * by issuing <code>write("element", false)</code> (or any of the other
+ * write-variants that allows specifying the <code>isEmpty</code> argument)
+ * and <code>writeEnd(false)</code>.</p>
+ *
+ * <p>Note: It is important that the values of <code>isEmpty</code> and
+ * <code>wasEmpty</code> match. Otherwise strange things might happen to
+ * the layout.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public interface Writer
+{
+ // TODO: This interface's design is not the best. Feel free to
+ // improve it as you like.
+
+ /** Writes the XML preamble. */
+ void writePreamble();
+
+ /** Writes the end of an XML tag.
+ *
+ * <p>If your tag has not generated any body text or child
+ * elements provide <code>true</code> as the argument to generate
+ * more space efficient variant of the tag.>/p>
+ *
+ * @param wasEmpty Whether the tag was empty or not.
+ */
+ void writeEnd(boolean wasEmpty);
+
+ /** Writes an XML tag without any attributes.
+ *
+ * @param tagName The name of the tag to write.
+ * @param empty Whether the element has child elements.
+ */
+ void write(String tagName, boolean empty);
+
+ /** Writes an XML tag with one attribute name and value.
+ *
+ * @param tagName The name of the tag to write.
+ * @param attributeName The name of attribute.
+ * @param attributeValue The attribute's value.
+ * @param empty Whether the element has child elements.
+ */
+ void write(String tagName, String attributeName, String attributeValue, boolean empty);
+
+ /** Writes an XML tag with multiple attributes and a body text.
+ *
+ * @param tagName The name of the tag to write.
+ * @param value The element's body content.
+ * @param attributeNames A set of attribute names.
+ * @param attributeValues A set of attribute values.
+ * @param empty Whether the element has child elements.
+ */
+ void write(String tagName, String value, String[] attributeNames,
+ String[] attributeValues, boolean empty);
+
+ /** Writes an XML tag with multiple attributes without a body text.
+ *
+ * @param tagName The name of the tag to write.
+ * @param attributeNames A set of attribute names.
+ * @param attributeValues A set of attribute values.
+ * @param empty Whether the element has child elements.
+ */
+ void write(String tagName, String[] attributeNames, String[] attributeValues, boolean empty);
+
+ /** Writes an XML tag with no attributes but with a body text
+ * that may have child elements.
+ *
+ * @param tagName The name of the tag to write.
+ * @param value The element's body content.
+ */
+ void write(String tagName, String value);
+
+ /** Writes an XML tag with no attributes but with a body text
+ * that does not have child elements.
+ *
+ * @param tagName The name of the tag to write.
+ * @param value The element's body content.
+ */
+ void writeNoChildren(String tagName, String value);
+
+ /** Writes the end of an XML tag that has no child elements.
+ *
+ * <p>Must be used in combination with {@link writeNoChildren} only.</p>
+ */
+ void writeEndNoChildren();
+
+ /** Forces the implementation to write some data.
+ */
+ void flush();
+
+ /** Closes the writer.
+ */
+ void close();
+}
diff --git a/gnu/java/beans/encoder/elements/ArrayInstantiation.java b/gnu/java/beans/encoder/elements/ArrayInstantiation.java
new file mode 100644
index 000000000..a9aef89c7
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/ArrayInstantiation.java
@@ -0,0 +1,74 @@
+/* ArrayInstantiation.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.ObjectId;
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting the instantiation of an array.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class ArrayInstantiation extends Element
+{
+ final String className;
+
+ final String lengthAsString;
+
+ public ArrayInstantiation(String newClassName, String newLengthAsString)
+ {
+ className = newClassName;
+ lengthAsString = newLengthAsString;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ ObjectId objectId = getId();
+ if (objectId.isUnused())
+ writer.write("array", new String[] { "class", "length" },
+ new String[] { className, lengthAsString }, isEmpty());
+ else
+ writer.write("array", new String[] { "id", "class", "length" },
+ new String[] { objectId.toString(), className,
+ lengthAsString }, isEmpty());
+
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/Array_Get.java b/gnu/java/beans/encoder/elements/Array_Get.java
new file mode 100644
index 000000000..ca2ce0fa6
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/Array_Get.java
@@ -0,0 +1,62 @@
+/* Array_Get.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/**
+ * Generates an XML element denoting the retrieval of an array value.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public class Array_Get extends Element
+{
+ final String indexAsString;
+
+ public Array_Get(String newIndexAsString)
+ {
+ indexAsString = newIndexAsString;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("void", "index", indexAsString, isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/Array_Set.java b/gnu/java/beans/encoder/elements/Array_Set.java
new file mode 100644
index 000000000..096232055
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/Array_Set.java
@@ -0,0 +1,57 @@
+/* Array_Set.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+public class Array_Set extends Element
+{
+ final String indexAsString;
+
+ public Array_Set(String newIndexAsString)
+ {
+ indexAsString = newIndexAsString;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("void", "index", indexAsString, isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/ClassResolution.java b/gnu/java/beans/encoder/elements/ClassResolution.java
new file mode 100644
index 000000000..8e640d183
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/ClassResolution.java
@@ -0,0 +1,67 @@
+/* ClassResolution.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting the resolution of a class.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class ClassResolution extends Element
+{
+ final String className;
+
+ public ClassResolution(String newClassName)
+ {
+ className = newClassName;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.writeNoChildren("class", className);
+ }
+
+ public void writeEnd(Writer writer)
+ {
+ writer.writeEndNoChildren();
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/Element.java b/gnu/java/beans/encoder/elements/Element.java
new file mode 100644
index 000000000..5681d2b76
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/Element.java
@@ -0,0 +1,157 @@
+/* Element.java -- Base class for object tree elements.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import gnu.java.beans.encoder.ObjectId;
+import gnu.java.beans.encoder.Writer;
+
+/** <code>Element</code> is the base class for the object tree elements.
+ *
+ * <p>It provides the neccessary infrastructure every element subclass
+ * needs in order to interact with the {@link gnu.java.beans.encoder.Root}
+ * class.</p>
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ */
+public abstract class Element
+{
+ /**
+ * Stores the child elements.
+ */
+ private LinkedList children = new LinkedList();
+
+ /**
+ * An optional ObjectId instance which is needed for certain subclasses
+ * only.
+ */
+ private ObjectId objectId;
+
+ /** Sets an {@link gnu.java.beans.encoder.ObjectId} instance in this
+ * <code>Element</code>.
+ *
+ * <p>This can only be done once.</p>
+ *
+ * @param objectId An ObjectId instance.
+ */
+ public final void initId(ObjectId objectId)
+ {
+ assert (this.objectId == null);
+ assert (objectId != null);
+
+ this.objectId = objectId;
+ }
+
+ /** Adds a child element to this <code>Element</code>.
+ *
+ * @param elem The new child.
+ */
+ public final void addChild(Element elem)
+ {
+ children.add(elem);
+ }
+
+ /** Removes the child element added last.
+ */
+ public final void removeLast()
+ {
+ children.removeLast();
+ }
+
+ /** Provides access to the child elements via an iterator.
+ *
+ * @return An iterator for the child elements.
+ */
+ public final Iterator iterator(){
+ return children.iterator();
+ }
+
+ /** Clears all the stored child elements.
+ *
+ */
+ public final void clear()
+ {
+ children.clear();
+ }
+
+ /** Returns whether this element contains child elements.
+ *
+ * <p>This method is useful to decide which formatting variant
+ * for the XML element can be chosen.</p>
+ *
+ * @return Whether the element has child elements.
+ */
+ public final boolean isEmpty()
+ {
+ return children.isEmpty();
+ }
+
+ /** Retrieves the element's {@link gnu.java.beans.encoder.ObjectId} instance
+ * if it has one.
+ *
+ * @return The ObjectId instance or <code>null</code>.
+ */
+ public final ObjectId getId()
+ {
+ return objectId;
+ }
+
+ /** Writes the opening XML tag.
+ *
+ * @param writer The writer to be used for XML writing.
+ */
+ public abstract void writeStart(Writer writer);
+
+ /** Writes the closing XML tag.
+ *
+ * <p>By default this does <code>writer.writeEnd(children.isEmpty())</code>.
+ * Override if neccessary, for example when using the
+ * {@link gnu.java.beans.encoder.Writer#writeNoChildren}</code> method
+ * variants.
+ *
+ * @param writer The writer to be used for XML writing.
+ */
+ public void writeEnd(Writer writer)
+ {
+ writer.writeEnd(children.isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/List_Get.java b/gnu/java/beans/encoder/elements/List_Get.java
new file mode 100644
index 000000000..e73afa8e9
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/List_Get.java
@@ -0,0 +1,56 @@
+/* List_Get.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting the retrieval of a list's element.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class List_Get extends Element
+{
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("object", "get");
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/List_Set.java b/gnu/java/beans/encoder/elements/List_Set.java
new file mode 100644
index 000000000..03c73fd20
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/List_Set.java
@@ -0,0 +1,56 @@
+/* List_Set.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting the setting of a list's element.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class List_Set extends Element
+{
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("object", "set");
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/MethodInvocation.java b/gnu/java/beans/encoder/elements/MethodInvocation.java
new file mode 100644
index 000000000..d5b317496
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/MethodInvocation.java
@@ -0,0 +1,62 @@
+/* MethodCall.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting a non-static method call.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class MethodInvocation extends Element
+{
+ final String methodName;
+
+ public MethodInvocation(String newMethodName)
+ {
+ methodName = newMethodName;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("void", "method", methodName, isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/NullObject.java b/gnu/java/beans/encoder/elements/NullObject.java
new file mode 100644
index 000000000..599c4d85f
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/NullObject.java
@@ -0,0 +1,61 @@
+/* NullObject.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting the <code>null</code> value.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class NullObject extends Element
+{
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("null", true);
+ }
+
+ public void writeEnd(Writer writer)
+ {
+ writer.writeEnd(true);
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/ObjectInstantiation.java b/gnu/java/beans/encoder/elements/ObjectInstantiation.java
new file mode 100644
index 000000000..692227d59
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/ObjectInstantiation.java
@@ -0,0 +1,68 @@
+/* ObjectInstantiation.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.ObjectId;
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting the instantiation of an object.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class ObjectInstantiation extends Element
+{
+ final String className;
+
+ public ObjectInstantiation(String newClassName)
+ {
+ className = newClassName;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ ObjectId objectId = getId();
+ if (objectId.isUnused())
+ writer.write("object", "class", className, isEmpty());
+ else
+ writer.write("object", new String[] { "id", "class" },
+ new String[] { objectId.toString(), className }, isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/ObjectReference.java b/gnu/java/beans/encoder/elements/ObjectReference.java
new file mode 100644
index 000000000..a44c2ee60
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/ObjectReference.java
@@ -0,0 +1,68 @@
+/* StringInstantiation.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.ObjectId;
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting referencing an existing object.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class ObjectReference extends Element
+{
+ final ObjectId id;
+
+ public ObjectReference(ObjectId newId)
+ {
+ id = newId;
+
+ // Initializing the Id here is making sure it gets
+ // actually used. This step modifies the Id instance
+ // in other elements.
+ id.init();
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("object", "idref", id.toString(), isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java b/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java
new file mode 100644
index 000000000..db08edbf8
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java
@@ -0,0 +1,69 @@
+/* PrimitiveInstantiation.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting a primitive data value.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class PrimitiveInstantiation extends Element
+{
+ final String primitiveName;
+
+ final String valueAsString;
+
+ public PrimitiveInstantiation(String newPrimitiveName, String newValueAsString)
+ {
+ primitiveName = newPrimitiveName;
+ valueAsString = newValueAsString;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.writeNoChildren(primitiveName, valueAsString);
+ }
+
+ public void writeEnd(Writer writer)
+ {
+ writer.writeEndNoChildren();
+ }
+}
diff --git a/gnu/java/beans/encoder/elements/StaticFieldAccess.java b/gnu/java/beans/encoder/elements/StaticFieldAccess.java
new file mode 100644
index 000000000..7ed935d49
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/StaticFieldAccess.java
@@ -0,0 +1,66 @@
+/* StaticFieldAccess.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/** Generates an XML element denoting a static method call.
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class StaticFieldAccess extends Element
+{
+ final String className;
+
+ final String fieldName;
+
+ public StaticFieldAccess(String newClassName, String newFieldName)
+ {
+ className = newClassName;
+ fieldName = newFieldName;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("object", new String[] { "class", "field" },
+ new String[] { className, fieldName }, isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/StaticMethodInvocation.java b/gnu/java/beans/encoder/elements/StaticMethodInvocation.java
new file mode 100644
index 000000000..40c46a534
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/StaticMethodInvocation.java
@@ -0,0 +1,67 @@
+/* StaticMethodCall.java
+ -- A class denoting an XML element which makes up a static method call.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+/**
+ *
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ *
+ */
+public class StaticMethodInvocation extends Element
+{
+ final String className;
+
+ final String methodName;
+
+ public StaticMethodInvocation(String newClassName, String newMethodName)
+ {
+ className = newClassName;
+ methodName = newMethodName;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.write("void", new String[] { "class", "method" },
+ new String[] { className, methodName }, isEmpty());
+ }
+
+}
diff --git a/gnu/java/beans/encoder/elements/StringReference.java b/gnu/java/beans/encoder/elements/StringReference.java
new file mode 100644
index 000000000..c368e6528
--- /dev/null
+++ b/gnu/java/beans/encoder/elements/StringReference.java
@@ -0,0 +1,63 @@
+/* StringInstantiation.java
+ -- A class denoting an XML element which retrieves an array element.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder.elements;
+
+import gnu.java.beans.encoder.Writer;
+
+public class StringReference extends Element
+{
+ final String string;
+
+ public StringReference(String newString)
+ {
+ string = newString;
+ }
+
+ public void writeStart(Writer writer)
+ {
+ writer.writeNoChildren("string", string);
+ }
+
+ public void writeEnd(Writer writer)
+ {
+ writer.writeEndNoChildren();
+ }
+
+}
diff --git a/gnu/java/net/CRLFInputStream.java b/gnu/java/net/CRLFInputStream.java
index d0f9e8c41..91fd840b8 100644
--- a/gnu/java/net/CRLFInputStream.java
+++ b/gnu/java/net/CRLFInputStream.java
@@ -128,7 +128,7 @@ public class CRLFInputStream
in.reset();
if (i != -1)
{
- l = in.read(b, off, i + 1); // read to CR
+ l = in.read(b, off, (i + 1) - off); // read to CR
in.read(); // skip LF
b[i] = LF; // fix CR as LF
}
diff --git a/gnu/java/net/PlainDatagramSocketImpl.java b/gnu/java/net/PlainDatagramSocketImpl.java
index 339b5561c..0fcd780df 100644
--- a/gnu/java/net/PlainDatagramSocketImpl.java
+++ b/gnu/java/net/PlainDatagramSocketImpl.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package gnu.java.net;
-import gnu.classpath.Configuration;
-
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocketImpl;
@@ -64,20 +62,7 @@ import java.net.SocketException;
*/
public final class PlainDatagramSocketImpl extends DatagramSocketImpl
{
- // Static initializer to load native library
- static
- {
- if (Configuration.INIT_LOAD_LIBRARY)
- {
- System.loadLibrary("javanet");
- }
- }
-
- /**
- * Option id for the IP_TTL (time to live) value.
- */
- private static final int IP_TTL = 0x1E61; // 7777
-
+
/**
* This is the actual underlying file descriptor
*/
@@ -98,6 +83,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
public PlainDatagramSocketImpl()
{
+ // Nothing to do here.
}
protected void finalize() throws Throwable
@@ -123,15 +109,48 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*
* @exception SocketException If an error occurs
*/
- protected synchronized native void bind(int port, InetAddress addr)
- throws SocketException;
+ protected synchronized void bind(int port, InetAddress addr)
+ throws SocketException
+ {
+ VMPlainDatagramSocketImpl.bind(this, port, addr);
+ }
/**
* Creates a new datagram socket
*
* @exception SocketException If an error occurs
*/
- protected synchronized native void create() throws SocketException;
+ protected synchronized void create() throws SocketException
+ {
+ VMPlainDatagramSocketImpl.create(this);
+ }
+
+ /**
+ * Connects to the remote address and port specified as arguments.
+ *
+ * @param addr The remote address to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception SocketException If an error occurs
+ */
+ protected void connect(InetAddress addr, int port) throws SocketException
+ {
+ VMPlainDatagramSocketImpl.connect(this, addr, port);
+ }
+
+ /**
+ * Disconnects the socket.
+ *
+ * @since 1.4
+ */
+ protected void disconnect()
+ {
+ synchronized (this)
+ {
+ if (native_fd != -1)
+ close();
+ }
+ }
/**
* Sets the Time to Live value for the socket
@@ -142,7 +161,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void setTimeToLive(int ttl) throws IOException
{
- setOption(IP_TTL, new Integer(ttl));
+ setOption(VMPlainDatagramSocketImpl.IP_TTL, new Integer(ttl));
}
/**
@@ -154,7 +173,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized int getTimeToLive() throws IOException
{
- Object obj = getOption(IP_TTL);
+ Object obj = getOption(VMPlainDatagramSocketImpl.IP_TTL);
if (! (obj instanceof Integer))
throw new IOException("Internal Error");
@@ -162,20 +181,6 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
return ((Integer) obj).intValue();
}
- /**
- * Sends a packet of data to a remote host
- *
- * @param addr The address to send to
- * @param port The port to send to
- * @param buf The buffer to send
- * @param offset The offset of the data in the buffer to send
- * @param len The length of the data to send
- *
- * @exception IOException If an error occurs
- */
- private native void sendto (InetAddress addr, int port,
- byte[] buf, int offset, int len)
- throws IOException;
/**
* Sends a packet of data to a remote host
@@ -186,12 +191,13 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected void send(DatagramPacket packet) throws IOException
{
- synchronized(SEND_LOCK)
+ if (native_fd != -1)
{
- sendto(packet.getAddress(), packet.getPort(), packet.getData(),
- packet.getOffset(), packet.getLength());
- }
-
+ synchronized(SEND_LOCK)
+ {
+ VMPlainDatagramSocketImpl.send(this, packet);
+ }
+ }
}
/**
@@ -206,18 +212,10 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
{
synchronized(RECEIVE_LOCK)
{
- receive0(packet);
+ VMPlainDatagramSocketImpl.receive(this, packet);
}
}
- /**
- * Native call to receive a UDP packet from the network
- *
- * @param packet The packet to fill in with the data received
- *
- * @exception IOException IOException If an error occurs
- */
- private native void receive0(DatagramPacket packet) throws IOException;
/**
* Sets the value of an option on the socket
@@ -227,8 +225,11 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*
* @exception SocketException If an error occurs
*/
- public synchronized native void setOption(int option_id, Object val)
- throws SocketException;
+ public synchronized void setOption(int option_id, Object val)
+ throws SocketException
+ {
+ VMPlainDatagramSocketImpl.setOption(this, option_id, val);
+ }
/**
* Retrieves the value of an option on the socket
@@ -239,13 +240,19 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*
* @exception SocketException If an error occurs
*/
- public synchronized native Object getOption(int option_id)
- throws SocketException;
+ public synchronized Object getOption(int option_id)
+ throws SocketException
+ {
+ return VMPlainDatagramSocketImpl.getOption(this, option_id);
+ }
/**
* Closes the socket
*/
- protected synchronized native void close();
+ protected synchronized void close()
+ {
+ VMPlainDatagramSocketImpl.close(this);
+ }
/**
* Gets the Time to Live value for the socket
@@ -282,7 +289,10 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*
* @exception IOException If an error occurs
*/
- protected synchronized native void join(InetAddress addr) throws IOException;
+ protected synchronized void join(InetAddress addr) throws IOException
+ {
+ VMPlainDatagramSocketImpl.join(this,addr);
+ }
/**
* Leaves a multicast group
@@ -291,7 +301,10 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*
* @exception IOException If an error occurs
*/
- protected synchronized native void leave(InetAddress addr) throws IOException;
+ protected synchronized void leave(InetAddress addr) throws IOException
+ {
+ VMPlainDatagramSocketImpl.leave(this, addr);
+ }
/**
* What does this method really do?
@@ -308,14 +321,14 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
}
public void joinGroup(SocketAddress address, NetworkInterface netIf)
+ throws IOException
{
- throw new InternalError
- ("PlainDatagramSocketImpl::joinGroup is not implemented");
+ VMPlainDatagramSocketImpl.joinGroup(this, address, netIf);
}
public void leaveGroup(SocketAddress address, NetworkInterface netIf)
+ throws IOException
{
- throw new InternalError
- ("PlainDatagramSocketImpl::leaveGroup is not implemented");
+ VMPlainDatagramSocketImpl.leaveGroup(this, address, netIf);
}
}
diff --git a/gnu/java/net/PlainSocketImpl.java b/gnu/java/net/PlainSocketImpl.java
index 05221ff88..47d05aa41 100644
--- a/gnu/java/net/PlainSocketImpl.java
+++ b/gnu/java/net/PlainSocketImpl.java
@@ -39,17 +39,13 @@ exception statement from your version. */
package gnu.java.net;
-import gnu.classpath.Configuration;
-
-import java.io.IOException;
import java.io.InputStream;
+import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
-import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
-import java.net.SocketOptions;
/**
* Written using on-line Java Platform 1.2 API Specification, as well
@@ -69,14 +65,6 @@ import java.net.SocketOptions;
*/
public final class PlainSocketImpl extends SocketImpl
{
- // Static initializer to load native library.
- static
- {
- if (Configuration.INIT_LOAD_LIBRARY)
- {
- System.loadLibrary("javanet");
- }
- }
/**
* The OS file handle representing the socket.
@@ -125,10 +113,11 @@ public final class PlainSocketImpl extends SocketImpl
}
/**
- * Default do nothing constructor
+ * Default do nothing constructor.
*/
public PlainSocketImpl()
{
+ // Nothing to do here.
}
protected void finalize() throws Throwable
@@ -142,6 +131,7 @@ public final class PlainSocketImpl extends SocketImpl
}
catch (IOException ex)
{
+ // Nothing we can do about it.
}
}
super.finalize();
@@ -158,121 +148,111 @@ public final class PlainSocketImpl extends SocketImpl
* Integer. The option_id parameter is one of the defined constants in
* this interface.
*
- * @param option_id The identifier of the option
- * @param val The value to set the option to
+ * @param optionId The identifier of the option
+ * @param value The value to set the option to
*
- * @exception SocketException If an error occurs
+ * @throws SocketException if an error occurs
*/
- public native void setOption(int optID, Object value) throws SocketException;
+ public void setOption(int optionId, Object value) throws SocketException
+ {
+ VMPlainSocketImpl.setOption(this, optionId, value);
+ }
/**
* Returns the current setting of the specified option. The Object returned
* will be an Integer for options that have integer values. The option_id
* is one of the defined constants in this interface.
*
- * @param option_id The option identifier
+ * @param optionId the option identifier
*
- * @return The current value of the option
+ * @return the current value of the option
*
- * @exception SocketException If an error occurs
+ * @throws SocketException if an error occurs
*/
- public native Object getOption(int optID) throws SocketException;
+ public Object getOption(int optionId) throws SocketException
+ {
+ return VMPlainSocketImpl.getOption(this, optionId);
+ }
- /**
- * Flushes the input stream and closes it. If you read from the input stream
- * after calling this method a <code>IOException</code> will be thrown.
- *
- * @throws IOException if an error occurs
- */
- public native void shutdownInput() throws IOException;
+ public void shutdownInput() throws IOException
+ {
+ VMPlainSocketImpl.shutdownInput(this);
+ }
- /**
- * Flushes the output stream and closes it. If you write to the output stream
- * after calling this method a <code>IOException</code> will be thrown.
- *
- * @throws IOException if an error occurs
- */
- public native void shutdownOutput() throws IOException;
+ public void shutdownOutput() throws IOException
+ {
+ VMPlainSocketImpl.shutdownOutput(this);
+ }
/**
* Creates a new socket that is not bound to any local address/port and
- * is not connected to any remote address/port. This will be created as
- * a stream socket if the stream parameter is true, or a datagram socket
- * if the stream parameter is false.
+ * is not connected to any remote address/port. The stream parameter will be
+ * ignored since PlainSocketImpl always is a stream socket. Datagram sockets
+ * are handled by PlainDatagramSocketImpl.
*
- * @param stream true for a stream socket, false for a datagram socket
+ * @param stream <code>true</code> for stream sockets, <code>false</code> for
+ * datagram sockets
*/
- protected synchronized native void create(boolean stream) throws IOException;
+ protected synchronized void create(boolean stream) throws IOException
+ {
+ VMPlainSocketImpl.create(this);
+ }
/**
* Connects to the remote hostname and port specified as arguments.
*
- * @param hostname The remote hostname to connect to
- * @param port The remote port to connect to
+ * @param hostname the remote hostname to connect to
+ * @param port the remote port to connect to
*
- * @exception IOException If an error occurs
+ * @throws IOException If an error occurs
*/
- protected synchronized void connect(String host, int port) throws IOException
+ protected synchronized void connect(String hostname, int port)
+ throws IOException
{
- connect(InetAddress.getByName(host), port);
+ connect(InetAddress.getByName(hostname), port);
}
/**
* Connects to the remote address and port specified as arguments.
*
- * @param addr The remote address to connect to
- * @param port The remote port to connect to
+ * @param addr the remote address to connect to
+ * @param port the remote port to connect to
*
- * @exception IOException If an error occurs
+ * @throws IOException If an error occurs
*/
- protected native void connect(InetAddress addr, int port) throws IOException;
+ protected void connect(InetAddress addr, int port) throws IOException
+ {
+ VMPlainSocketImpl.connect(this, addr, port);
+ }
/**
* Connects to the remote socket address with a specified timeout.
*
- * @param timeout The timeout to use for this connect, 0 means infinite.
+ * @param address the remote address to connect to
+ * @param timeout the timeout to use for this connect, 0 means infinite.
*
- * @exception IOException If an error occurs
+ * @throws IOException If an error occurs
*/
- protected synchronized void connect(SocketAddress address, int timeout) throws IOException
+ protected synchronized void connect(SocketAddress address, int timeout)
+ throws IOException
{
- InetSocketAddress sockAddr = (InetSocketAddress) address;
- InetAddress addr = sockAddr.getAddress();
-
- if (addr == null)
- throw new IllegalArgumentException("address is unresolved: " + sockAddr);
-
- int port = sockAddr.getPort();
-
- if (timeout < 0)
- throw new IllegalArgumentException("negative timeout");
-
- Object oldTimeoutObj = null;
-
- try
- {
- oldTimeoutObj = this.getOption (SocketOptions.SO_TIMEOUT);
- this.setOption (SocketOptions.SO_TIMEOUT, new Integer (timeout));
- connect (addr, port);
- }
- finally
- {
- if (oldTimeoutObj != null)
- this.setOption (SocketOptions.SO_TIMEOUT, oldTimeoutObj);
- }
+ VMPlainSocketImpl.connect(this, address, timeout);
}
/**
* Binds to the specified port on the specified addr. Note that this addr
* must represent a local IP address. **** How bind to INADDR_ANY? ****
*
- * @param addr The address to bind to
- * @param port The port number to bind to
+ * @param addr the address to bind to
+ * @param port the port number to bind to
*
- * @exception IOException If an error occurs
+ * @throws IOException if an error occurs
*/
- protected synchronized native void bind(InetAddress addr, int port)
- throws IOException;
+ protected synchronized void bind(InetAddress addr, int port)
+ throws IOException
+ {
+ VMPlainSocketImpl.bind(this, addr, port);
+ }
/**
* Starts listening for connections on a socket. The queuelen parameter
@@ -282,10 +262,13 @@ public final class PlainSocketImpl extends SocketImpl
*
* @param queuelen The length of the pending connection queue
*
- * @exception IOException If an error occurs
+ * @throws IOException If an error occurs
*/
- protected synchronized native void listen(int queuelen)
- throws IOException;
+ protected synchronized void listen(int queuelen)
+ throws IOException
+ {
+ VMPlainSocketImpl.listen(this, queuelen);
+ }
/**
* Accepts a new connection on this socket and returns in in the
@@ -293,33 +276,44 @@ public final class PlainSocketImpl extends SocketImpl
*
* @param impl The SocketImpl object to accept this connection.
*/
- protected synchronized native void accept(SocketImpl impl)
- throws IOException;
+ protected synchronized void accept(SocketImpl impl)
+ throws IOException
+ {
+ VMPlainSocketImpl.accept(this, impl);
+ }
/**
* Returns the number of bytes that the caller can read from this socket
* without blocking.
*
- * @return The number of readable bytes before blocking
+ * @return the number of readable bytes before blocking
*
- * @exception IOException If an error occurs
+ * @throws IOException if an error occurs
*/
- protected native int available() throws IOException;
+ protected int available() throws IOException
+ {
+ return VMPlainSocketImpl.available(this);
+ }
/**
* Closes the socket. This will cause any InputStream or OutputStream
* objects for this Socket to be closed as well.
+ *
* <p>
* Note that if the SO_LINGER option is set on this socket, then the
* operation could block.
+ * </p>
*
- * @exception IOException If an error occurs
+ * @throws IOException if an error occurs
*/
- protected native void close() throws IOException;
+ protected void close() throws IOException
+ {
+ VMPlainSocketImpl.close(this);
+ }
public void sendUrgentData(int data)
{
- throw new InternalError ("PlainSocketImpl::sendUrgentData not implemented");
+ VMPlainSocketImpl.sendUrgendData(this, data);
}
/**
@@ -327,22 +321,53 @@ public final class PlainSocketImpl extends SocketImpl
* the connection. Reads up to len bytes of data into the buffer
* buf starting at offset bytes into the buffer.
*
- * @return The actual number of bytes read or -1 if end of stream.
+ * @return the actual number of bytes read or -1 if end of stream.
*
- * @exception IOException If an error occurs
+ * @throws IOException if an error occurs
+ */
+ protected int read(byte[] buf, int offset, int len)
+ throws IOException
+ {
+ return VMPlainSocketImpl.read(this, buf, offset, len);
+ }
+
+ /**
+ * Internal method used by SocketInputStream for reading data from
+ * the connection. Reads and returns one byte of data.
+ *
+ * @return the read byte
+ *
+ * @throws IOException if an error occurs
*/
- protected native int read(byte[] buf, int offset, int len)
- throws IOException;
+ protected int read()
+ throws IOException
+ {
+ return VMPlainSocketImpl.read(this);
+ }
/**
* Internal method used by SocketOuputStream for writing data to
* the connection. Writes up to len bytes of data from the buffer
* buf starting at offset bytes into the buffer.
*
- * @exception IOException If an error occurs
+ * @throws IOException If an error occurs
+ */
+ protected void write(byte[] buf, int offset, int len)
+ throws IOException
+ {
+ VMPlainSocketImpl.write(this, buf, offset, len);
+ }
+
+ /**
+ * Internal method used by SocketOuputStream for writing data to
+ * the connection. Writes up one byte to the socket.
+ *
+ * @throws IOException If an error occurs
*/
- protected native void write(byte[] buf, int offset, int len)
- throws IOException;
+ protected void write(int data) throws IOException
+ {
+ VMPlainSocketImpl.write(this, data);
+ }
/**
* Returns an InputStream object for reading from this socket. This will
@@ -356,7 +381,7 @@ public final class PlainSocketImpl extends SocketImpl
{
if (in == null)
in = new SocketInputStream();
-
+
return in;
}
@@ -372,7 +397,7 @@ public final class PlainSocketImpl extends SocketImpl
{
if (out == null)
out = new SocketOutputStream();
-
+
return out;
}
@@ -380,7 +405,7 @@ public final class PlainSocketImpl extends SocketImpl
* This class contains an implementation of <code>InputStream</code> for
* sockets. It in an internal only class used by <code>PlainSocketImpl</code>.
*
- * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
*/
final class SocketInputStream
extends InputStream
@@ -412,13 +437,7 @@ public final class PlainSocketImpl extends SocketImpl
*/
public int read() throws IOException
{
- byte buf[] = new byte [1];
- int bytes_read = read(buf, 0, 1);
-
- if (bytes_read == -1)
- return -1;
-
- return buf[0] & 0xFF;
+ return PlainSocketImpl.this.read();
}
/**
@@ -450,7 +469,7 @@ public final class PlainSocketImpl extends SocketImpl
* <code>getOutputStream method</code>. It expects only to be used in that
* context.
*
- * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
*/
final class SocketOutputStream
extends OutputStream
@@ -476,8 +495,7 @@ public final class PlainSocketImpl extends SocketImpl
*/
public void write(int b) throws IOException
{
- byte buf[] = { (byte) b };
- write(buf, 0, 1);
+ PlainSocketImpl.this.write(b);
}
/**
diff --git a/gnu/java/nio/DatagramChannelImpl.java b/gnu/java/nio/DatagramChannelImpl.java
index 51c7031fe..4687bf3f5 100644
--- a/gnu/java/nio/DatagramChannelImpl.java
+++ b/gnu/java/nio/DatagramChannelImpl.java
@@ -201,7 +201,7 @@ public final class DatagramChannelImpl extends DatagramChannel
try
{
DatagramPacket packet;
- int len = dst.capacity() - dst.position();
+ int len = dst.remaining();
if (dst.hasArray())
{
diff --git a/gnu/java/nio/SelectorImpl.java b/gnu/java/nio/SelectorImpl.java
index f0f56f9c3..5d4e93156 100644
--- a/gnu/java/nio/SelectorImpl.java
+++ b/gnu/java/nio/SelectorImpl.java
@@ -43,6 +43,7 @@ import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
@@ -284,19 +285,18 @@ public class SelectorImpl extends AbstractSelector
// Set new ready write ops
for (int i = 0; i < write.length; i++)
{
- if (key.getNativeFD() == write[i])
- {
- ops = ops | SelectionKey.OP_WRITE;
-
- // if (key.channel ().isConnected ())
- // {
- // ops = ops | SelectionKey.OP_WRITE;
- // }
- // else
- // {
- // ops = ops | SelectionKey.OP_CONNECT;
- // }
- }
+ if (key.getNativeFD() == write[i])
+ {
+ if (key.channel() instanceof SocketChannel)
+ {
+ if (((SocketChannel) key.channel ()).isConnected ())
+ ops = ops | SelectionKey.OP_WRITE;
+ else
+ ops = ops | SelectionKey.OP_CONNECT;
+ }
+ else
+ ops = ops | SelectionKey.OP_WRITE;
+ }
}
// FIXME: We dont handle exceptional file descriptors yet.
diff --git a/gnu/java/nio/SocketChannelImpl.java b/gnu/java/nio/SocketChannelImpl.java
index fcddbd6c3..680eba2f9 100644
--- a/gnu/java/nio/SocketChannelImpl.java
+++ b/gnu/java/nio/SocketChannelImpl.java
@@ -220,7 +220,7 @@ public final class SocketChannelImpl extends SocketChannel
int offset = 0;
InputStream input = socket.getInputStream();
int available = input.available();
- int len = dst.capacity() - dst.position();
+ int len = dst.remaining();
if ((! isBlocking()) && available == 0)
return 0;
diff --git a/gnu/java/nio/charset/Provider.java b/gnu/java/nio/charset/Provider.java
index 3f25c5988..c7f7ed278 100644
--- a/gnu/java/nio/charset/Provider.java
+++ b/gnu/java/nio/charset/Provider.java
@@ -39,6 +39,8 @@ package gnu.java.nio.charset;
import java.nio.charset.Charset;
import java.nio.charset.spi.CharsetProvider;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -232,8 +234,16 @@ public final class Provider extends CharsetProvider
public static synchronized Provider provider ()
{
+ // The default provider is safe to instantiate.
if (singleton == null)
- singleton = new Provider ();
+ singleton = (Provider) AccessController.doPrivileged
+ (new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return new Provider();
+ }
+ });
return singleton;
}
}
diff --git a/gnu/java/security/Engine.java b/gnu/java/security/Engine.java
index b75de5caa..4b6bd10d9 100644
--- a/gnu/java/security/Engine.java
+++ b/gnu/java/security/Engine.java
@@ -1,5 +1,5 @@
/* Engine -- generic getInstance method.
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -130,7 +130,14 @@ public final class Engine
Provider provider, Object[] initArgs)
throws InvocationTargetException, NoSuchAlgorithmException
{
- if (service == null || algorithm == null
+ if (service != null)
+ service = service.trim();
+
+ if (algorithm != null)
+ algorithm = algorithm.trim();
+
+ if (service == null || service.length() == 0
+ || algorithm == null || algorithm.length() == 0
|| provider == null || initArgs == null)
throw new IllegalArgumentException();
diff --git a/gnu/java/util/WeakIdentityHashMap.java b/gnu/java/util/WeakIdentityHashMap.java
new file mode 100644
index 000000000..210a3d8c5
--- /dev/null
+++ b/gnu/java/util/WeakIdentityHashMap.java
@@ -0,0 +1,862 @@
+/* WeakIdentityHashMap -- an identity hashtable that keeps only weak references
+ to its keys, allowing the virtual machine to reclaim them
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.util;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * A weak hash map has only weak references to the key. This means that it
+ * allows the key to be garbage collected if it is not used otherwise. If
+ * this happens, the entry will eventually disappear from the map,
+ * asynchronously.
+ *
+ * <p>Other strange behaviors to be aware of: The size of this map may
+ * spontaneously shrink (even if you use a synchronized map and synchronize
+ * it); it behaves as if another thread removes entries from this table
+ * without synchronization. The entry set returned by <code>entrySet</code>
+ * has similar phenomenons: The size may spontaneously shrink, or an
+ * entry, that was in the set before, suddenly disappears.
+ *
+ * <p>A weak hash map is not meant for caches; use a normal map, with
+ * soft references as values instead, or try {@link LinkedHashMap}.
+ *
+ * <p>The weak hash map supports null values and null keys. The null key
+ * is never deleted from the map (except explictly of course). The
+ * performance of the methods are similar to that of a hash map.
+ *
+ * <p>The value objects are strongly referenced by this table. So if a
+ * value object maintains a strong reference to the key (either direct
+ * or indirect) the key will never be removed from this map. According
+ * to Sun, this problem may be fixed in a future release. It is not
+ * possible to do it with the jdk 1.2 reference model, though.
+ *
+ * @author Jochen Hoenicke
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @author Jeroen Frijters
+ *
+ * @see HashMap
+ * @see WeakReference
+ * @see WeakHashMap
+ * @see IdentityHashMap
+ * @see LinkedHashMap
+ */
+public class WeakIdentityHashMap extends AbstractMap implements Map
+{
+ /**
+ * The default capacity for an instance of HashMap.
+ * Sun's documentation mildly suggests that this (11) is the correct
+ * value.
+ */
+ private static final int DEFAULT_CAPACITY = 11;
+
+ /**
+ * The default load factor of a HashMap.
+ */
+ private static final float DEFAULT_LOAD_FACTOR = 0.75F;
+
+ /**
+ * This is used instead of the key value <i>null</i>. It is needed
+ * to distinguish between an null key and a removed key.
+ */
+ // Package visible for use by nested classes.
+ static final Object NULL_KEY = new Object();
+
+ /**
+ * The reference queue where our buckets (which are WeakReferences) are
+ * registered to.
+ */
+ private final ReferenceQueue queue;
+
+ /**
+ * The number of entries in this hash map.
+ */
+ // Package visible for use by nested classes.
+ int size;
+
+ /**
+ * The load factor of this WeakIdentityHashMap. This is the maximum ratio of
+ * size versus number of buckets. If size grows the number of buckets
+ * must grow, too.
+ */
+ private float loadFactor;
+
+ /**
+ * The rounded product of the capacity (i.e. number of buckets) and
+ * the load factor. When the number of elements exceeds the
+ * threshold, the HashMap calls <code>rehash()</code>.
+ */
+ private int threshold;
+
+ /**
+ * The number of structural modifications. This is used by
+ * iterators, to see if they should fail. This doesn't count
+ * the silent key removals, when a weak reference is cleared
+ * by the garbage collection. Instead the iterators must make
+ * sure to have strong references to the entries they rely on.
+ */
+ // Package visible for use by nested classes.
+ int modCount;
+
+ /**
+ * The entry set. There is only one instance per hashmap, namely
+ * theEntrySet. Note that the entry set may silently shrink, just
+ * like the WeakIdentityHashMap.
+ */
+ private final class WeakEntrySet extends AbstractSet
+ {
+ /**
+ * Non-private constructor to reduce bytecode emitted.
+ */
+ WeakEntrySet()
+ {
+ }
+
+ /**
+ * Returns the size of this set.
+ *
+ * @return the set size
+ */
+ public int size()
+ {
+ return size;
+ }
+
+ /**
+ * Returns an iterator for all entries.
+ *
+ * @return an Entry iterator
+ */
+ public Iterator iterator()
+ {
+ return new Iterator()
+ {
+ /**
+ * The entry that was returned by the last
+ * <code>next()</code> call. This is also the entry whose
+ * bucket should be removed by the <code>remove</code> call. <br>
+ *
+ * It is null, if the <code>next</code> method wasn't
+ * called yet, or if the entry was already removed. <br>
+ *
+ * Remembering this entry here will also prevent it from
+ * being removed under us, since the entry strongly refers
+ * to the key.
+ */
+ WeakBucket.WeakEntry lastEntry;
+
+ /**
+ * The entry that will be returned by the next
+ * <code>next()</code> call. It is <code>null</code> if there
+ * is no further entry. <br>
+ *
+ * Remembering this entry here will also prevent it from
+ * being removed under us, since the entry strongly refers
+ * to the key.
+ */
+ WeakBucket.WeakEntry nextEntry = findNext(null);
+
+ /**
+ * The known number of modification to the list, if it differs
+ * from the real number, we throw an exception.
+ */
+ int knownMod = modCount;
+
+ /**
+ * Check the known number of modification to the number of
+ * modifications of the table. If it differs from the real
+ * number, we throw an exception.
+ * @throws ConcurrentModificationException if the number
+ * of modifications doesn't match.
+ */
+ private void checkMod()
+ {
+ // This method will get inlined.
+ cleanQueue();
+ if (knownMod != modCount)
+ throw new ConcurrentModificationException(knownMod + " != "
+ + modCount);
+ }
+
+ /**
+ * Get a strong reference to the next entry after
+ * lastBucket.
+ * @param lastEntry the previous bucket, or null if we should
+ * get the first entry.
+ * @return the next entry.
+ */
+ private WeakBucket.WeakEntry findNext(WeakBucket.WeakEntry lastEntry)
+ {
+ int slot;
+ WeakBucket nextBucket;
+ if (lastEntry != null)
+ {
+ nextBucket = lastEntry.getBucket().next;
+ slot = lastEntry.getBucket().slot;
+ }
+ else
+ {
+ nextBucket = buckets[0];
+ slot = 0;
+ }
+
+ while (true)
+ {
+ while (nextBucket != null)
+ {
+ WeakBucket.WeakEntry entry = nextBucket.getEntry();
+ if (entry != null)
+ // This is the next entry.
+ return entry;
+
+ // Entry was cleared, try next.
+ nextBucket = nextBucket.next;
+ }
+
+ slot++;
+ if (slot == buckets.length)
+ // No more buckets, we are through.
+ return null;
+
+ nextBucket = buckets[slot];
+ }
+ }
+
+ /**
+ * Checks if there are more entries.
+ * @return true, iff there are more elements.
+ * @throws ConcurrentModificationException if the hash map was
+ * modified.
+ */
+ public boolean hasNext()
+ {
+ checkMod();
+ return nextEntry != null;
+ }
+
+ /**
+ * Returns the next entry.
+ * @return the next entry.
+ * @throws ConcurrentModificationException if the hash map was
+ * modified.
+ * @throws NoSuchElementException if there is no entry.
+ */
+ public Object next()
+ {
+ checkMod();
+ if (nextEntry == null)
+ throw new NoSuchElementException();
+ lastEntry = nextEntry;
+ nextEntry = findNext(lastEntry);
+ return lastEntry;
+ }
+
+ /**
+ * Removes the last returned entry from this set. This will
+ * also remove the bucket of the underlying weak hash map.
+ * @throws ConcurrentModificationException if the hash map was
+ * modified.
+ * @throws IllegalStateException if <code>next()</code> was
+ * never called or the element was already removed.
+ */
+ public void remove()
+ {
+ checkMod();
+ if (lastEntry == null)
+ throw new IllegalStateException();
+ modCount++;
+ internalRemove(lastEntry.getBucket());
+ lastEntry = null;
+ knownMod++;
+ }
+ };
+ }
+ }
+
+ /**
+ * A bucket is a weak reference to the key, that contains a strong
+ * reference to the value, a pointer to the next bucket and its slot
+ * number. <br>
+ *
+ * It would be cleaner to have a WeakReference as field, instead of
+ * extending it, but if a weak reference gets cleared, we only get
+ * the weak reference (by queue.poll) and wouldn't know where to
+ * look for this reference in the hashtable, to remove that entry.
+ *
+ * @author Jochen Hoenicke
+ */
+ private static class WeakBucket extends WeakReference
+ {
+ /**
+ * The value of this entry. The key is stored in the weak
+ * reference that we extend.
+ */
+ Object value;
+
+ /**
+ * The next bucket describing another entry that uses the same
+ * slot.
+ */
+ WeakBucket next;
+
+ /**
+ * The slot of this entry. This should be
+ * <code>Math.abs(key.hashCode() % buckets.length)</code>.
+ *
+ * But since the key may be silently removed we have to remember
+ * the slot number.
+ *
+ * If this bucket was removed the slot is -1. This marker will
+ * prevent the bucket from being removed twice.
+ */
+ int slot;
+
+ /**
+ * Creates a new bucket for the given key/value pair and the specified
+ * slot.
+ * @param key the key
+ * @param queue the queue the weak reference belongs to
+ * @param value the value
+ * @param slot the slot. This must match the slot where this bucket
+ * will be enqueued.
+ */
+ public WeakBucket(Object key, ReferenceQueue queue, Object value,
+ int slot)
+ {
+ super(key, queue);
+ this.value = value;
+ this.slot = slot;
+ }
+
+ /**
+ * This class gives the <code>Entry</code> representation of the
+ * current bucket. It also keeps a strong reference to the
+ * key; bad things may happen otherwise.
+ */
+ class WeakEntry implements Map.Entry
+ {
+ /**
+ * The strong ref to the key.
+ */
+ Object key;
+
+ /**
+ * Creates a new entry for the key.
+ * @param key the key
+ */
+ public WeakEntry(Object key)
+ {
+ this.key = key;
+ }
+
+ /**
+ * Returns the underlying bucket.
+ * @return the owning bucket
+ */
+ public WeakBucket getBucket()
+ {
+ return WeakBucket.this;
+ }
+
+ /**
+ * Returns the key.
+ * @return the key
+ */
+ public Object getKey()
+ {
+ return key == NULL_KEY ? null : key;
+ }
+
+ /**
+ * Returns the value.
+ * @return the value
+ */
+ public Object getValue()
+ {
+ return value;
+ }
+
+ /**
+ * This changes the value. This change takes place in
+ * the underlying hash map.
+ * @param newVal the new value
+ * @return the old value
+ */
+ public Object setValue(Object newVal)
+ {
+ Object oldVal = value;
+ value = newVal;
+ return oldVal;
+ }
+
+ /**
+ * The hashCode as specified in the Entry interface.
+ * @return the hash code
+ */
+ public int hashCode()
+ {
+ return System.identityHashCode(key)
+ ^ (value == null ? 0 : value.hashCode());
+ }
+
+ /**
+ * The equals method as specified in the Entry interface.
+ * @param o the object to compare to
+ * @return true iff o represents the same key/value pair
+ */
+ public boolean equals(Object o)
+ {
+ if (o instanceof Map.Entry)
+ {
+ Map.Entry e = (Map.Entry) o;
+ return getKey() == e.getKey()
+ && (value == null ? e.getValue() == null
+ : value.equals(e.getValue()));
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ return getKey() + "=" + value;
+ }
+ }
+
+ /**
+ * This returns the entry stored in this bucket, or null, if the
+ * bucket got cleared in the mean time.
+ * @return the Entry for this bucket, if it exists
+ */
+ WeakEntry getEntry()
+ {
+ final Object key = this.get();
+ if (key == null)
+ return null;
+ return new WeakEntry(key);
+ }
+ }
+
+ /**
+ * The entry set returned by <code>entrySet()</code>.
+ */
+ private final WeakEntrySet theEntrySet;
+
+ /**
+ * The hash buckets. These are linked lists. Package visible for use in
+ * nested classes.
+ */
+ WeakBucket[] buckets;
+
+ /**
+ * Creates a new weak hash map with default load factor and default
+ * capacity.
+ */
+ public WeakIdentityHashMap()
+ {
+ this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
+ }
+
+ /**
+ * Creates a new weak hash map with default load factor and the given
+ * capacity.
+ * @param initialCapacity the initial capacity
+ * @throws IllegalArgumentException if initialCapacity is negative
+ */
+ public WeakIdentityHashMap(int initialCapacity)
+ {
+ this(initialCapacity, DEFAULT_LOAD_FACTOR);
+ }
+
+ /**
+ * Creates a new weak hash map with the given initial capacity and
+ * load factor.
+ * @param initialCapacity the initial capacity.
+ * @param loadFactor the load factor (see class description of HashMap).
+ * @throws IllegalArgumentException if initialCapacity is negative, or
+ * loadFactor is non-positive
+ */
+ public WeakIdentityHashMap(int initialCapacity, float loadFactor)
+ {
+ // Check loadFactor for NaN as well.
+ if (initialCapacity < 0 || ! (loadFactor > 0))
+ throw new IllegalArgumentException();
+ if (initialCapacity == 0)
+ initialCapacity = 1;
+ this.loadFactor = loadFactor;
+ threshold = (int) (initialCapacity * loadFactor);
+ theEntrySet = new WeakEntrySet();
+ queue = new ReferenceQueue();
+ buckets = new WeakBucket[initialCapacity];
+ }
+
+ /**
+ * Construct a new WeakIdentityHashMap with the same mappings as the given map.
+ * The WeakIdentityHashMap has a default load factor of 0.75.
+ *
+ * @param m the map to copy
+ * @throws NullPointerException if m is null
+ * @since 1.3
+ */
+ public WeakIdentityHashMap(Map m)
+ {
+ this(m.size(), DEFAULT_LOAD_FACTOR);
+ putAll(m);
+ }
+
+ /**
+ * Simply hashes a non-null Object to its array index.
+ * @param key the key to hash
+ * @return its slot number
+ */
+ private int hash(Object key)
+ {
+ return Math.abs(System.identityHashCode(key) % buckets.length);
+ }
+
+ /**
+ * Cleans the reference queue. This will poll all references (which
+ * are WeakBuckets) from the queue and remove them from this map.
+ * This will not change modCount, even if it modifies the map. The
+ * iterators have to make sure that nothing bad happens. <br>
+ *
+ * Currently the iterator maintains a strong reference to the key, so
+ * that is no problem.
+ */
+ // Package visible for use by nested classes.
+ void cleanQueue()
+ {
+ Object bucket = queue.poll();
+ while (bucket != null)
+ {
+ internalRemove((WeakBucket) bucket);
+ bucket = queue.poll();
+ }
+ }
+
+ /**
+ * Rehashes this hashtable. This will be called by the
+ * <code>add()</code> method if the size grows beyond the threshold.
+ * It will grow the bucket size at least by factor two and allocates
+ * new buckets.
+ */
+ private void rehash()
+ {
+ WeakBucket[] oldBuckets = buckets;
+ int newsize = buckets.length * 2 + 1; // XXX should be prime.
+ threshold = (int) (newsize * loadFactor);
+ buckets = new WeakBucket[newsize];
+
+ // Now we have to insert the buckets again.
+ for (int i = 0; i < oldBuckets.length; i++)
+ {
+ WeakBucket bucket = oldBuckets[i];
+ WeakBucket nextBucket;
+ while (bucket != null)
+ {
+ nextBucket = bucket.next;
+
+ Object key = bucket.get();
+ if (key == null)
+ {
+ // This bucket should be removed; it is probably
+ // already on the reference queue. We don't insert it
+ // at all, and mark it as cleared.
+ bucket.slot = -1;
+ size--;
+ }
+ else
+ {
+ // Add this bucket to its new slot.
+ int slot = hash(key);
+ bucket.slot = slot;
+ bucket.next = buckets[slot];
+ buckets[slot] = bucket;
+ }
+ bucket = nextBucket;
+ }
+ }
+ }
+
+ /**
+ * Finds the entry corresponding to key. Since it returns an Entry
+ * it will also prevent the key from being removed under us.
+ * @param key the key, may be null
+ * @return The WeakBucket.WeakEntry or null, if the key wasn't found.
+ */
+ private WeakBucket.WeakEntry internalGet(Object key)
+ {
+ if (key == null)
+ key = NULL_KEY;
+ int slot = hash(key);
+ WeakBucket bucket = buckets[slot];
+ while (bucket != null)
+ {
+ WeakBucket.WeakEntry entry = bucket.getEntry();
+ if (entry != null && key == entry.key)
+ return entry;
+
+ bucket = bucket.next;
+ }
+ return null;
+ }
+
+ /**
+ * Adds a new key/value pair to the hash map.
+ * @param key the key. This mustn't exists in the map. It may be null.
+ * @param value the value.
+ */
+ private void internalAdd(Object key, Object value)
+ {
+ if (key == null)
+ key = NULL_KEY;
+ int slot = hash(key);
+ WeakBucket bucket = new WeakBucket(key, queue, value, slot);
+ bucket.next = buckets[slot];
+ buckets[slot] = bucket;
+ size++;
+ }
+
+ /**
+ * Removes a bucket from this hash map, if it wasn't removed before
+ * (e.g. one time through rehashing and one time through reference queue).
+ * Package visible for use in nested classes.
+ *
+ * @param bucket the bucket to remove.
+ */
+ void internalRemove(WeakBucket bucket)
+ {
+ int slot = bucket.slot;
+ if (slot == -1)
+ // This bucket was already removed.
+ return;
+
+ // Mark the bucket as removed. This is necessary, since the
+ // bucket may be enqueued later by the garbage collection, and
+ // internalRemove will be called a second time.
+ bucket.slot = -1;
+
+ WeakBucket prev = null;
+ WeakBucket next = buckets[slot];
+ while (next != bucket)
+ {
+ if (next == null)
+ throw new InternalError("WeakIdentityHashMap in inconsistent state");
+ prev = next;
+ next = prev.next;
+ }
+ if (prev == null)
+ buckets[slot] = bucket.next;
+ else
+ prev.next = bucket.next;
+
+ size--;
+ }
+
+ /**
+ * Returns the size of this hash map. Note that the size() may shrink
+ * spontaneously, if the some of the keys were only weakly reachable.
+ * @return the number of entries in this hash map.
+ */
+ public int size()
+ {
+ cleanQueue();
+ return size;
+ }
+
+ /**
+ * Tells if the map is empty. Note that the result may change
+ * spontanously, if all of the keys were only weakly reachable.
+ * @return true, iff the map is empty.
+ */
+ public boolean isEmpty()
+ {
+ cleanQueue();
+ return size == 0;
+ }
+
+ /**
+ * Tells if the map contains the given key. Note that the result
+ * may change spontanously, if the key was only weakly
+ * reachable.
+ * @param key the key to look for
+ * @return true, iff the map contains an entry for the given key.
+ */
+ public boolean containsKey(Object key)
+ {
+ cleanQueue();
+ return internalGet(key) != null;
+ }
+
+ /**
+ * Gets the value the key is mapped to.
+ * @return the value the key was mapped to. It returns null if
+ * the key wasn't in this map, or if the mapped value was
+ * explicitly set to null.
+ */
+ public Object get(Object key)
+ {
+ cleanQueue();
+ WeakBucket.WeakEntry entry = internalGet(key);
+ return entry == null ? null : entry.getValue();
+ }
+
+ /**
+ * Adds a new key/value mapping to this map.
+ * @param key the key, may be null
+ * @param value the value, may be null
+ * @return the value the key was mapped to previously. It returns
+ * null if the key wasn't in this map, or if the mapped value
+ * was explicitly set to null.
+ */
+ public Object put(Object key, Object value)
+ {
+ cleanQueue();
+ WeakBucket.WeakEntry entry = internalGet(key);
+ if (entry != null)
+ return entry.setValue(value);
+
+ modCount++;
+ if (size >= threshold)
+ rehash();
+
+ internalAdd(key, value);
+ return null;
+ }
+
+ /**
+ * Removes the key and the corresponding value from this map.
+ * @param key the key. This may be null.
+ * @return the value the key was mapped to previously. It returns
+ * null if the key wasn't in this map, or if the mapped value was
+ * explicitly set to null.
+ */
+ public Object remove(Object key)
+ {
+ cleanQueue();
+ WeakBucket.WeakEntry entry = internalGet(key);
+ if (entry == null)
+ return null;
+
+ modCount++;
+ internalRemove(entry.getBucket());
+ return entry.getValue();
+ }
+
+ /**
+ * Returns a set representation of the entries in this map. This
+ * set will not have strong references to the keys, so they can be
+ * silently removed. The returned set has therefore the same
+ * strange behaviour (shrinking size(), disappearing entries) as
+ * this weak hash map.
+ * @return a set representation of the entries.
+ */
+ public Set entrySet()
+ {
+ cleanQueue();
+ return theEntrySet;
+ }
+
+ /**
+ * Clears all entries from this map.
+ */
+ public void clear()
+ {
+ super.clear();
+ }
+
+ /**
+ * Returns true if the map contains at least one key which points to
+ * the specified object as a value. Note that the result
+ * may change spontanously, if its key was only weakly reachable.
+ * @param value the value to search for
+ * @return true if it is found in the set.
+ */
+ public boolean containsValue(Object value)
+ {
+ cleanQueue();
+ return super.containsValue(value);
+ }
+
+ /**
+ * Returns a set representation of the keys in this map. This
+ * set will not have strong references to the keys, so they can be
+ * silently removed. The returned set has therefore the same
+ * strange behaviour (shrinking size(), disappearing entries) as
+ * this weak hash map.
+ * @return a set representation of the keys.
+ */
+ public Set keySet()
+ {
+ cleanQueue();
+ return super.keySet();
+ }
+
+ /**
+ * Puts all of the mappings from the given map into this one. If the
+ * key already exists in this map, its value is replaced.
+ * @param m the map to copy in
+ */
+ public void putAll(Map m)
+ {
+ super.putAll(m);
+ }
+
+ /**
+ * Returns a collection representation of the values in this map. This
+ * collection will not have strong references to the keys, so mappings
+ * can be silently removed. The returned collection has therefore the same
+ * strange behaviour (shrinking size(), disappearing entries) as
+ * this weak hash map.
+ * @return a collection representation of the values.
+ */
+ public Collection values()
+ {
+ cleanQueue();
+ return super.values();
+ }
+} // class WeakIdentityHashMap