Imported GNU Classpath 0.20

Imported GNU Classpath 0.20
       * Makefile.am (AM_CPPFLAGS): Add classpath/include.
       * java/nio/charset/spi/CharsetProvider.java: New override file.
       * java/security/Security.java: Likewise.
       * sources.am: Regenerated.
       * Makefile.in: Likewise.

From-SVN: r109831
This commit is contained in:
Mark Wielaard
2006-01-17 18:09:40 +00:00
parent bcb36c3e02
commit 2127637945
444 changed files with 75778 additions and 30731 deletions
@@ -40,6 +40,8 @@ package gnu.java.awt.image;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -55,6 +57,7 @@ public abstract class ImageDecoder implements ImageProducer
int offset;
int length;
InputStream input;
DataInput datainput;
static
{
@@ -79,6 +82,11 @@ public abstract class ImageDecoder implements ImageProducer
this.input = is;
}
public ImageDecoder (DataInput datainput)
{
this.datainput = datainput;
}
public ImageDecoder (byte[] imagedata, int imageoffset, int imagelength)
{
data = imagedata;
@@ -119,6 +127,8 @@ public abstract class ImageDecoder implements ImageProducer
{
if (url != null)
input = url.openStream();
else if (datainput != null)
input = new DataInputStreamWrapper(datainput);
else
{
if (filename != null)
@@ -153,4 +163,26 @@ public abstract class ImageDecoder implements ImageProducer
}
public abstract void produce (Vector v, InputStream is) throws IOException;
private static class DataInputStreamWrapper extends InputStream
{
private final DataInput datainput;
DataInputStreamWrapper(DataInput datainput)
{
this.datainput = datainput;
}
public int read() throws IOException
{
try
{
return datainput.readByte() & 0xFF;
}
catch (EOFException eofe)
{
return -1;
}
}
}
}
@@ -48,7 +48,6 @@ import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.SystemColor;
import java.awt.image.ImageObserver;
import java.text.AttributedCharacterIterator;
@@ -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()
{
return new GdkGraphics (this);
GdkGraphics copy = cached;
if (copy == null)
copy = new GdkGraphics(this);
else
{
copy.copyState(this);
cached = null;
}
return copy;
}
public native void dispose();
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()
{
if (parent != null)
{
parent.cached = this;
parent = null;
}
else
nativeDispose();
}
/**
* 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)
@@ -248,9 +294,8 @@ public class GdkGraphics extends Graphics
public void drawString (String str, int x, int y)
{
drawString(getFontPeer(), str, x, y);
}
}
public void drawString (AttributedCharacterIterator ci, int x, int y)
{
throw new Error ("not implemented");
@@ -419,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);
}
}
@@ -180,11 +180,14 @@ public class GdkGraphics2D extends Graphics2D
else
fg = new Color(g.fg.getRGB());
if (g.bg.getAlpha() != -1)
bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(),
g.bg.getAlpha());
else
bg = new Color(g.bg.getRGB());
if (g.bg != null)
{
if (g.bg.getAlpha() != -1)
bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(),
g.bg.getAlpha());
else
bg = new Color(g.bg.getRGB());
}
if (g.clip == null)
clip = null;
@@ -1088,6 +1091,8 @@ public class GdkGraphics2D extends Graphics2D
public void setBackground(Color c)
{
if (c == null)
c = Color.WHITE;
bg = c;
}
@@ -47,6 +47,7 @@ import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
@@ -102,6 +103,11 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
0x00ff0000,
0x0000ff00,
0x000000ff);
public GdkPixbufDecoder (DataInput datainput)
{
super (datainput);
}
public GdkPixbufDecoder (InputStream in)
{
super (in);
@@ -630,7 +636,14 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
boolean ignoreMetadata)
{
super.setInput(input, seekForwardOnly, ignoreMetadata);
dec = new GdkPixbufDecoder((InputStream) getInput());
Object get = getInput();
if (get instanceof InputStream)
dec = new GdkPixbufDecoder((InputStream) get);
else if (get instanceof DataInput)
dec = new GdkPixbufDecoder((DataInput) get);
else
throw new IllegalArgumentException("input object not supported: "
+ get);
}
public BufferedImage read(int imageIndex, ImageReadParam param)
@@ -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
}));
}
}
}
}
}
@@ -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() });
}
}
@@ -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() }));
}
}
}
@@ -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 + "]";
}
}
@@ -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()
{
}
}
@@ -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()
{
}
}
@@ -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) }));
}
}
}
@@ -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));
}
}
@@ -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() }));
}
}
@@ -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");
}
}
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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()
{
}
}
@@ -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);
}
}
@@ -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();
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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();
}
}
@@ -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());
}
}
@@ -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");
}
}
@@ -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");
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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();
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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();
}
}
@@ -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
}
@@ -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);
}
}
@@ -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 native int read(byte[] buf, int offset, int len)
throws IOException;
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 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 native void write(byte[] buf, int offset, int len)
throws IOException;
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 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);
}
/**
@@ -1,5 +1,5 @@
/* FileChannelImpl.java --
Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -301,8 +301,10 @@ public final class FileChannelImpl extends FileChannel
else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE)
{
nmode = mode == MapMode.READ_WRITE ? '+' : 'c';
if ((this.mode & (READ|WRITE)) != (READ|WRITE))
if ((this.mode & WRITE) != WRITE)
throw new NonWritableChannelException();
if ((this.mode & READ) != READ)
throw new NonReadableChannelException();
}
else
throw new IllegalArgumentException ("mode: " + mode);
@@ -1,5 +1,5 @@
/* Provider.java --
Copyright (C) 2002, 2005 Free Software Foundation, Inc.
Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -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;
@@ -47,6 +49,11 @@ import java.util.Iterator;
* Charset provider for the required charsets. Used by
* {@link Charset#charsetForName} and * {@link Charset#availableCharsets}.
*
* Note: This class is a privileged class, because it can be instantiated without
* requiring the RuntimePermission("charsetProvider"). There is a check in
* java.nio.charset.spi.CharsetProvider to skip the security check if the provider
* is an instance of this class.
*
* @author Jesse Rosenstock
* @author Robert Schuster (thebohemian@gmx.net)
* @see Charset
@@ -55,14 +62,6 @@ public final class Provider extends CharsetProvider
{
private static Provider singleton;
static
{
synchronized (Provider.class)
{
singleton = null;
}
}
/**
* Map from charset name to charset canonical name. The strings
* are all lower-case to allow case-insensitive retrieval of
@@ -232,8 +231,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;
}
}
@@ -1,5 +1,5 @@
/* IconvProvider.java --
Copyright (C) 2005 Free Software Foundation, Inc.
Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -48,20 +48,17 @@ import java.util.Vector;
/**
* Charset provider wrapping iconv.
*
* Note: This class is a privileged class, because it can be instantiated without
* requiring the RuntimePermission("charsetProvider"). There is a check in
* java.nio.charset.spi.CharsetProvider to skip the security check if the provider
* is an instance of this class.
*
* @author Sven de Marothy
*/
public final class IconvProvider extends CharsetProvider
{
private static IconvProvider singleton;
static
{
synchronized (IconvProvider.class)
{
singleton = null;
}
}
// Declaring the construtor public may violate the use of singleton.
// But it must be public so that an instance of this class can be
// created by Class.newInstance(), which is the case when this provider is
@@ -47,6 +47,7 @@ import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.ConnectException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.ObjID;
@@ -195,7 +196,7 @@ public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash
conn = manager.getConnection();
}
catch (IOException e1) {
throw new RemoteException("connection failed to host: " + manager.serverName, e1);
throw new ConnectException("connection failed to host: " + manager.serverName, e1);
}
//obj: useless?
@@ -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();
@@ -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