http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/core/src/flex/messaging/io/amf/Amf3Input.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/io/amf/Amf3Input.java b/core/src/flex/messaging/io/amf/Amf3Input.java deleted file mode 100644 index 0e62b88..0000000 --- a/core/src/flex/messaging/io/amf/Amf3Input.java +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package flex.messaging.io.amf; - -import java.io.ByteArrayOutputStream; -import java.io.Externalizable; -import java.io.IOException; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Date; -import java.util.Dictionary; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; - -import flex.messaging.io.PropertyProxy; -import flex.messaging.io.SerializationContext; -import flex.messaging.io.SerializationException; -import flex.messaging.io.UnknownTypeException; -import flex.messaging.io.amf.AmfTrace.VectorType; -import flex.messaging.util.ClassUtil; -import flex.messaging.util.Trace; - -/** - * Reads AMF 3 formatted data stream. - * <p> - * This class intends to matches the Flash Player 8 C++ code - * in avmglue/DataIO.cpp - * </p> - * - * - */ -public class Amf3Input extends AbstractAmfInput implements Amf3Types -{ - /** - * - */ - protected List objectTable; - - /** - * - */ - protected List stringTable; - - /** - * - */ - protected List traitsTable; - - public Amf3Input(SerializationContext context) - { - super(context); - - stringTable = new ArrayList(64); - objectTable = new ArrayList(64); - traitsTable = new ArrayList(10); - } - - /** - * Reset should be called before reading a top level object, - * such as a new header or a new body. - */ - @Override - public void reset() - { - super.reset(); - stringTable.clear(); - objectTable.clear(); - traitsTable.clear(); - } - - public Object saveObjectTable() - { - Object table = objectTable; - objectTable = new ArrayList(64); - return table; - } - - public void restoreObjectTable(Object table) - { - objectTable = (ArrayList) table; - } - - public Object saveTraitsTable() - { - Object table = traitsTable; - traitsTable = new ArrayList(10); - return table; - } - - public void restoreTraitsTable(Object table) - { - traitsTable = (ArrayList) table; - } - - public Object saveStringTable() - { - Object table = stringTable; - stringTable = new ArrayList(64); - return table; - } - - public void restoreStringTable(Object table) - { - stringTable = (ArrayList) table; - } - - /** - * Public entry point to read a top level AMF Object, such as - * a header value or a message body. - * @return Object the object read - * @throws ClassNotFoundException, IOException when reading object process failed - */ - public Object readObject() throws ClassNotFoundException, IOException - { - int type = in.readByte(); - Object value = readObjectValue(type); - return value; - } - - /** - * - */ - protected Object readObjectValue(int type) throws ClassNotFoundException, IOException - { - Object value = null; - - switch (type) - { - case kStringType: - ClassUtil.validateCreation(String.class); - - value = readString(); - if (isDebug) - trace.writeString((String)value); - break; - - case kObjectType: - value = readScriptObject(); - break; - - case kArrayType: - value = readArray(); - break; - - case kFalseType: - ClassUtil.validateCreation(Boolean.class); - - value = Boolean.FALSE; - - if (isDebug) - trace.write(value); - break; - - case kTrueType: - ClassUtil.validateCreation(Boolean.class); - - value = Boolean.TRUE; - - if (isDebug) - trace.write(value); - break; - - case kIntegerType: - ClassUtil.validateCreation(Integer.class); - - int i = readUInt29(); - // Symmetric with writing an integer to fix sign bits for negative values... - i = (i << 3) >> 3; - value = new Integer(i); - - if (isDebug) - trace.write(value); - break; - - case kDoubleType: - value = Double.valueOf(readDouble()); - break; - - case kUndefinedType: - if (isDebug) - trace.writeUndefined(); - break; - - case kNullType: - if (isDebug) - trace.writeNull(); - break; - - case kXMLType: - case kAvmPlusXmlType: - value = readXml(); - break; - - case kDateType: - value = readDate(); - break; - - case kByteArrayType: - value = readByteArray(); - break; - - case kDictionaryType: - value = readDictionary(); - break; - - case kTypedVectorInt: - case kTypedVectorUint: - case kTypedVectorDouble: - case kTypedVectorObject: - value = readTypedVector(type); - break; - default: - // Unknown object type tag {type} - UnknownTypeException ex = new UnknownTypeException(); - ex.setMessage(10301, new Object[]{new Integer(type)}); - throw ex; - } - - return value; - } - - /** {@inheritDoc} */ - @Override - public double readDouble() throws IOException - { - ClassUtil.validateCreation(Double.class); - - double d = super.readDouble(); - if (isDebug) - trace.write(d); - return d; - } - - /** - * - */ - protected String readString() throws IOException - { - int ref = readUInt29(); - if ((ref & 1) == 0) // This is a reference - return getStringReference(ref >> 1); - - int len = (ref >> 1); // Read the string in - - // writeString() special cases the empty string - // to avoid creating a reference. - if (0 == len) - return EMPTY_STRING; - - String str = readUTF(len); - - stringTable.add(str); // Remember String - - return str; - } - - /** - * Deserialize the bits of a date-time value w/o a prefixing type byte. - */ - protected Date readDate() throws IOException - { - ClassUtil.validateCreation(Date.class); - - int ref = readUInt29(); - if ((ref & 1) == 0) // This is a reference - return (Date)getObjectReference(ref >> 1); - - long time = (long)in.readDouble(); - - Date d = new Date(time); - - objectTable.add(d); //Remember Date - - if (isDebug) - trace.write(d); - - return d; - } - - protected Object readDictionary() throws IOException, ClassNotFoundException - { - int ref = readUInt29(); - - if ((ref & 1) == 0) // This is a reference. - return getObjectReference(ref >> 1); - - readBoolean(); // usingWeakTypes - irrelevant in Java. - int len = (ref >> 1); - - Dictionary dictionary = (Hashtable)ClassUtil.createDefaultInstance(Hashtable.class, null, true /*validate*/); - - objectTable.add(dictionary); // Remember the object. - - if (isDebug) - trace.startAMFDictionary(objectTable.size() - 1); - - for (int i = 0; i < len; i++) - { - if (isDebug) trace.startDictionaryElement(); - Object key = readObjectOneLevelDown(true); - - if (isDebug) trace.addDictionaryEquals(); - Object value = readObjectOneLevelDown(true); - ClassUtil.validateAssignment(dictionary, key != null? key.toString() : null, value); - dictionary.put(key, value); - } - - if (isDebug) - trace.endAMFDictionary(); - - return dictionary; - } - - protected Object readTypedVector(int type) throws IOException, ClassNotFoundException - { - int ref = readUInt29(); - - if ((ref & 1) == 0) // This is a reference. - return getObjectReference(ref >> 1); - - int len = (ref >> 1); - boolean fixed = readBoolean(); - - Object vector = null; - switch (type) - { - case kTypedVectorInt: - vector = readTypedIntVector(len, fixed); - break; - case kTypedVectorUint: - vector = readTypedUintVector(len, fixed); - break; - case kTypedVectorDouble: - vector = readTypedDoubleVector(len, fixed); - break; - case kTypedVectorObject: - vector = readTypedObjectVector(len, fixed); - break; - default: - // Unknown object type tag {type} - UnknownTypeException ex = new UnknownTypeException(); - ex.setMessage(10301, new Object[]{Integer.valueOf(type)}); - throw ex; - } - return vector; - } - - @SuppressWarnings("unchecked") - protected Object readTypedIntVector(int len, boolean fixed) throws IOException - { - // Don't instantiate Array right away with the supplied size if it is more - // than INITIAL_ARRAY_CAPACITY in case the supplied size has been tampered. - boolean useListTemporarily = false; - - Object vector; - if (fixed) - { - useListTemporarily = len > INITIAL_COLLECTION_CAPACITY; - if (useListTemporarily) - { - ClassUtil.validateCreation(ArrayList.class); - vector = new ArrayList<Integer>(INITIAL_COLLECTION_CAPACITY); - } - else - { - ClassUtil.validateCreation(Integer[].class); - vector = new Integer[len]; - } - } - else - { - ClassUtil.validateCreation(ArrayList.class); - int initialCapacity = len < INITIAL_COLLECTION_CAPACITY? len : INITIAL_COLLECTION_CAPACITY; - vector = new ArrayList<Integer>(initialCapacity); - } - - int objectId = rememberObject(vector); - - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.INT); - - for (int i = 0; i < len; i++) - { - if (isDebug) - trace.arrayElement(i); - - ClassUtil.validateCreation(Integer.class); - int value = readInt(); - - if (isDebug) - trace.write(value); - - Integer item = Integer.valueOf(value); - - ClassUtil.validateAssignment(vector, i, item); - if (vector instanceof Integer[]) - Array.set(vector, i, item); - else - ((List<Integer>)vector).add(item); - } - - if (useListTemporarily) - { - vector = ((ArrayList<Integer>)vector).toArray(); - objectTable.set(objectId, vector); - } - - if (isDebug) - trace.endAMFVector(); - - return vector; - } - - @SuppressWarnings("unchecked") - protected Object readTypedUintVector(int len, boolean fixed) throws IOException - { - // Don't instantiate Array right away with the supplied size if it is more - // than INITIAL_ARRAY_CAPACITY in case the supplied size has been tampered. - boolean useListTemporarily = false; - - Object vector; - if (fixed) - { - useListTemporarily = len > INITIAL_COLLECTION_CAPACITY; - if (useListTemporarily) - { - ClassUtil.validateCreation(ArrayList.class); - vector = new ArrayList<Long>(INITIAL_COLLECTION_CAPACITY); - } - else - { - ClassUtil.validateCreation(Long[].class); - vector = new Long[len]; - } - } - else - { - ClassUtil.validateCreation(ArrayList.class); - int initialCapacity = len < INITIAL_COLLECTION_CAPACITY? len : INITIAL_COLLECTION_CAPACITY; - vector = new ArrayList<Long>(initialCapacity); - } - - int objectId = rememberObject(vector); - - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.UINT); - - for (int i = 0; i < len; i++) - { - if (isDebug) - trace.arrayElement(i); - - ClassUtil.validateCreation(Long.class); - - long value = (long) (in.readByte() & 0xFF) << 24L; - value += (long) (in.readByte() & 0xFF) << 16L; - value += (long) (in.readByte() & 0xFF) << 8L; - value += (in.readByte() & 0xFF); - - if (isDebug) - trace.write(value); - - Long item = Long.valueOf(value); - - ClassUtil.validateAssignment(vector, i, item); - if (vector instanceof Long[]) - Array.set(vector, i, item); - else - ((List<Long>)vector).add(item); - } - - if (useListTemporarily) - { - vector = ((ArrayList<Long>)vector).toArray(); - objectTable.set(objectId, vector); - } - - if (isDebug) - trace.endAMFVector(); - - return vector; - } - - @SuppressWarnings("unchecked") - protected Object readTypedDoubleVector(int len, boolean fixed) throws IOException - { - // Don't instantiate Array right away with the supplied size if it is more - // than INITIAL_ARRAY_CAPACITY in case the supplied size has been tampered. - boolean useListTemporarily = false; - - Object vector; - if (fixed) - { - useListTemporarily = len > INITIAL_COLLECTION_CAPACITY; - if (useListTemporarily) - { - ClassUtil.validateCreation(ArrayList.class); - vector = new ArrayList<Double>(INITIAL_COLLECTION_CAPACITY); - } - else - { - ClassUtil.validateCreation(Double[].class); - vector = new Double[len]; - } - } - else - { - ClassUtil.validateCreation(ArrayList.class); - int initialCapacity = len < INITIAL_COLLECTION_CAPACITY? len : INITIAL_COLLECTION_CAPACITY; - vector = new ArrayList<Double>(initialCapacity); - } - - int objectId = rememberObject(vector); - - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.DOUBLE); - - for (int i = 0; i < len; i++) - { - if (isDebug) - trace.arrayElement(i); - - Double item = Double.valueOf(readDouble()); - - ClassUtil.validateAssignment(vector, i, item); - if (vector instanceof Double[]) - Array.set(vector, i, item); - else - ((List<Double>)vector).add(item); - } - - if (useListTemporarily) - { - vector = ((ArrayList<Double>)vector).toArray(); - objectTable.set(objectId, vector); - } - - if (isDebug) - trace.endAMFVector(); - - return vector; - } - - @SuppressWarnings("unchecked") - protected Object readTypedObjectVector(int len, boolean fixed) throws IOException, ClassNotFoundException - { - // TODO - Class name is always empty for some reason, need to figure out if this is expected. - String className = readString(); - if (className == null || className.length() == 0 || className.equals(EMPTY_STRING)) - className = Object.class.getName(); - - // Don't instantiate Array right away with the supplied size if it is more - // than INITIAL_ARRAY_CAPACITY in case the supplied size has been tampered. - boolean useListTemporarily = false; - - Object vector; - if (fixed) - { - useListTemporarily = len > INITIAL_COLLECTION_CAPACITY; - if (useListTemporarily) - { - ClassUtil.validateCreation(ArrayList.class); - vector = new ArrayList<Object>(INITIAL_COLLECTION_CAPACITY); - } - else - { - ClassUtil.validateCreation(Object[].class); - vector = new Object[len]; - } - } - else - { - ClassUtil.validateCreation(ArrayList.class); - int initialCapacity = len < INITIAL_COLLECTION_CAPACITY? len : INITIAL_COLLECTION_CAPACITY; - vector = new ArrayList<Object>(initialCapacity); - } - - int objectId = rememberObject(vector); - - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.OBJECT); - - for (int i = 0; i < len; i++) - { - if (isDebug) - trace.arrayElement(i); - Object item = readObjectOneLevelDown(true); - ClassUtil.validateAssignment(vector, i, item); - if (vector instanceof Object[]) - Array.set(vector, i, item); - else - ((List<Object>)vector).add(item); - } - - if (useListTemporarily) - { - vector = ((ArrayList<Object>)vector).toArray(); - objectTable.set(objectId, vector); - } - - if (isDebug) - trace.endAMFVector(); - - return vector; - } - - /** - * - */ - protected Object readArray() throws ClassNotFoundException, IOException - { - int ref = readUInt29(); - - if ((ref & 1) == 0) // This is a reference. - return getObjectReference(ref >> 1); - - int len = (ref >> 1); - Object array = null; - - // First, look for any string based keys. If any non-ordinal indices were used, - // or if the Array is sparse, we represent the structure as a Map. - Map map = null; - for (; ;) - { - String name = readString(); - if (name == null || name.length() == 0) - break; - - if (map == null) - { - map = (HashMap)ClassUtil.createDefaultInstance(HashMap.class, null, true /*validate*/); - array = map; - - //Remember Object - objectTable.add(array); - - if (isDebug) - trace.startECMAArray(objectTable.size() - 1); - } - - if (isDebug) - trace.namedElement(name); - Object value = readObjectOneLevelDown(true); - ClassUtil.validateAssignment(map, name, value); - map.put(name, value); - } - - // If we didn't find any string based keys, we have a dense Array, so we - // represent the structure as a List. - if (map == null) - { - // Don't instantiate List/Array right away with the supplied size if it is more than - // INITIAL_ARRAY_CAPACITY in case the supplied size has been tampered. This at least - // requires the user to pass in the actual objects for the List/Array to grow beyond. - boolean useListTemporarily = false; - - // Legacy Flex 1.5 behavior was to return a java.util.Collection for Array - if (context.legacyCollection || len > INITIAL_COLLECTION_CAPACITY) - { - useListTemporarily = !context.legacyCollection; - ClassUtil.validateCreation(ArrayList.class); - int initialCapacity = len < INITIAL_COLLECTION_CAPACITY? len : INITIAL_COLLECTION_CAPACITY; - array = new ArrayList(initialCapacity); - } - // Flex 2+ behavior is to return Object[] for AS3 Array - else - { - ClassUtil.validateCreation(Object[].class); - array = new Object[len]; - } - int objectId = rememberObject(array); // Remember the List/Object[]. - - if (isDebug) - trace.startAMFArray(objectTable.size() - 1); - - for (int i = 0; i < len; i++) - { - if (isDebug) - trace.arrayElement(i); - Object item = readObjectOneLevelDown(true); - ClassUtil.validateAssignment(array, i, item); - if (array instanceof ArrayList) - ((ArrayList)array).add(item); - else - Array.set(array, i, item); - } - - if (useListTemporarily) - { - array = ((ArrayList)array).toArray(); - objectTable.set(objectId, array); - } - } - else - { - for (int i = 0; i < len; i++) - { - if (isDebug) - trace.arrayElement(i); - Object item = readObjectOneLevelDown(true); - String key = Integer.toString(i); - ClassUtil.validateAssignment(map, key, item); - map.put(key, item); - } - } - - if (isDebug) - trace.endAMFArray(); - - return array; - } - - /** - * - */ - protected Object readScriptObject() throws ClassNotFoundException, IOException - { - int ref = readUInt29(); - - if ((ref & 1) == 0) - return getObjectReference(ref >> 1); - - TraitsInfo ti = readTraits(ref); - String className = ti.getClassName(); - boolean externalizable = ti.isExternalizable(); - - // Prepare the parameters for createObjectInstance(). Use an array as a holder - // to simulate two 'by-reference' parameters className and (initially null) proxy - Object[] params = new Object[] {className, null}; - Object object = createObjectInstance(params); - - // Retrieve any changes to the className and the proxy parameters - className = (String)params[0]; - PropertyProxy proxy = (PropertyProxy)params[1]; - - // Remember our instance in the object table - int objectId = rememberObject(object); - - if (externalizable) - { - readExternalizable(className, object); - } - else - { - if (isDebug) - { - trace.startAMFObject(className, objectTable.size() - 1); - } - - boolean isCollectionClass = isCollectionClass(object); - int len = ti.getProperties().size(); - - for (int i = 0; i < len; i++) - { - String propName = ti.getProperty(i); - - if (isDebug) - trace.namedElement(propName); - Object value = readObjectOneLevelDown(isCollectionClass); - proxy.setValue(object, propName, value); - } - - if (ti.isDynamic()) - { - for (; ;) - { - String name = readString(); - if (name == null || name.length() == 0) break; - - if (isDebug) - trace.namedElement(name); - Object value = readObjectOneLevelDown(isCollectionClass); - proxy.setValue(object, name, value); - } - } - } - - if (isDebug) - trace.endAMFObject(); - - // This lets the BeanProxy substitute a new instance into the BeanProxy - // at the end of the serialization. You might for example create a Map, store up - // the properties, then construct the instance based on that. Note that this does - // not support recursive references to the parent object however. - Object newObj = proxy.instanceComplete(object); - - // TODO: It is possible we gave out references to the - // temporary object. it would be possible to warn users about - // that problem by tracking if we read any references to this object - // in the readObject call above. - if (newObj != object) - { - objectTable.set(objectId, newObj); - object = newObj; - } - - return object; - } - - /** - * - */ - protected void readExternalizable(String className, Object object) throws ClassNotFoundException, IOException - { - if (object instanceof Externalizable) - { - ClassUtil.validateCreation(Externalizable.class); - - if (isDebug) - trace.startExternalizableObject(className, objectTable.size() - 1); - - ((Externalizable)object).readExternal(this); - } - else - { - //Class '{className}' must implement java.io.Externalizable to receive client IExternalizable instances. - SerializationException ex = new SerializationException(); - ex.setMessage(10305, new Object[] {object.getClass().getName()}); - throw ex; - } - } - - /** - * - */ - protected byte[] readByteArray() throws IOException - { - ClassUtil.validateCreation(byte[].class); - - int ref = readUInt29(); - if ((ref & 1) == 0) - return (byte[])getObjectReference(ref >> 1); - - int len = (ref >> 1); - int initialCapacity = len < INITIAL_COLLECTION_CAPACITY? len : INITIAL_COLLECTION_CAPACITY; - ByteArrayOutputStream outStream = new ByteArrayOutputStream(initialCapacity); - for (int i = 0; i < len; i++) - outStream.write(in.read()); - - byte[] ba = outStream.toByteArray(); - objectTable.add(ba); - - if (isDebug) - trace.startByteArray(objectTable.size() - 1, len); - - return ba; - } - - /** - * - */ - protected TraitsInfo readTraits(int ref) throws IOException - { - if ((ref & 3) == 1) // This is a reference - return getTraitReference(ref >> 2); - - boolean externalizable = ((ref & 4) == 4); - boolean dynamic = ((ref & 8) == 8); - int count = (ref >> 4); /* uint29 */ - String className = readString(); - - TraitsInfo ti = new TraitsInfo(className, dynamic, externalizable, count); - - // Remember Trait Info - traitsTable.add(ti); - - for (int i = 0; i < count; i++) - { - String propName = readString(); - ti.addProperty(propName); - } - - return ti; - } - - /** - * - */ - protected String readUTF(int utflen) throws IOException - { - checkUTFLength(utflen); - // We should just read the bytes into a buffer - byte[] bytearr = new byte[utflen]; - - in.readFully(bytearr, 0, utflen); - // It is UTF-8 encoding, directly use new String(bytes, "utf-8"); - String s = new String(bytearr, "utf-8"); - return s; - } - - /** - * AMF 3 represents smaller integers with fewer bytes using the most - * significant bit of each byte. The worst case uses 32-bits - * to represent a 29-bit number, which is what we would have - * done with no compression. - * <pre> - * 0x00000000 - 0x0000007F : 0xxxxxxx - * 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx - * 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx - * 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx - * 0x40000000 - 0xFFFFFFFF : throw range exception - * </pre> - * - * @return A int capable of holding an unsigned 29 bit integer. - * @throws IOException - * - */ - protected int readUInt29() throws IOException - { - int value; - - // Each byte must be treated as unsigned - int b = in.readByte() & 0xFF; - - if (b < 128) - return b; - - value = (b & 0x7F) << 7; - b = in.readByte() & 0xFF; - - if (b < 128) - return (value | b); - - value = (value | (b & 0x7F)) << 7; - b = in.readByte() & 0xFF; - - if (b < 128) - return (value | b); - - value = (value | (b & 0x7F)) << 8; - b = in.readByte() & 0xFF; - - return (value | b); - } - - /** - * - */ - protected Object readXml() throws IOException - { - String xml = null; - - int ref = readUInt29(); - - if ((ref & 1) == 0) - { - // This is a reference - xml = (String)getObjectReference(ref >> 1); - } - else - { - // Read the string in - int len = (ref >> 1); - - // writeString() special case the empty string - // for speed. Do add a reference - if (0 == len) - xml = (String)ClassUtil.createDefaultInstance(String.class, null); - else - xml = readUTF(len); - - //Remember Object - objectTable.add(xml); - - if (isDebug) - trace.write(xml); - } - - return stringToDocument(xml); - } - - /** - * - */ - protected Object getObjectReference(int ref) - { - if (isDebug) - trace.writeRef(ref); - - return objectTable.get(ref); - } - - /** - * - */ - protected String getStringReference(int ref) - { - String str = (String)stringTable.get(ref); - - if (Trace.amf && isDebug) - trace.writeStringRef(ref); - - return str; - } - - /** - * - */ - protected TraitsInfo getTraitReference(int ref) - { - if (Trace.amf && isDebug) - trace.writeTraitsInfoRef(ref); - - return (TraitsInfo)traitsTable.get(ref); - } - - /** - * Remember a deserialized object so that you can use it later through a reference. - */ - protected int rememberObject(Object obj) - { - int id = objectTable.size(); - objectTable.add(obj); - return id; - } - - - protected Object readObjectOneLevelDown(boolean nestCollectionLevelDown) throws ClassNotFoundException, IOException - { - increaseNestObjectLevel(); - if (nestCollectionLevelDown) - increaseNestCollectionLevel(); - Object value = readObject(); - decreaseNestObjectLevel(); - if (nestCollectionLevelDown) - decreaseNestCollectionLevel(); - return value; - } -} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/core/src/flex/messaging/io/amf/Amf3Output.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/io/amf/Amf3Output.java b/core/src/flex/messaging/io/amf/Amf3Output.java deleted file mode 100644 index 7919530..0000000 --- a/core/src/flex/messaging/io/amf/Amf3Output.java +++ /dev/null @@ -1,1376 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package flex.messaging.io.amf; - -import flex.messaging.MessageException; -import flex.messaging.io.ArrayCollection; -import flex.messaging.io.BeanProxy; -import flex.messaging.io.PagedRowSet; -import flex.messaging.io.PropertyProxy; -import flex.messaging.io.PropertyProxyRegistry; -import flex.messaging.io.SerializationContext; -import flex.messaging.io.SerializationDescriptor; -import flex.messaging.io.StatusInfoProxy; -import flex.messaging.io.amf.AmfTrace.VectorType; -import flex.messaging.util.Trace; -import org.w3c.dom.Document; - -import javax.sql.RowSet; -import java.io.Externalizable; -import java.io.IOException; -import java.lang.reflect.Array; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.Dictionary; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * Serializes data to an output stream using the new - * AMF 3 format. - * <p> - * This class intends to match the Flash Player 8 C++ code - * in avmglue/DataIO.cpp - * </p> - * - * - */ -public class Amf3Output extends AbstractAmfOutput implements Amf3Types -{ - /** - * - */ - protected IdentityHashMap<Object, Integer> objectTable; - - /** - * - */ - protected HashMap<TraitsInfo, Integer> traitsTable; - - /** - * - */ - protected HashMap<String, Integer> stringTable; - - public Amf3Output(SerializationContext context) - { - super(context); - context.supportDatesByReference = true; - } - - public void reset() - { - super.reset(); - if (objectTable != null) - objectTable.clear(); - if (traitsTable != null) - traitsTable.clear(); - if (stringTable != null) - stringTable.clear(); - } - - // - // java.io.ObjectOutput IMPLEMENTATIONS - // - - /** - * Serialize an Object using AMF 3. - * @param o the object to write - * @throws IOException if the write failed - */ - public void writeObject(Object o) throws IOException - { - if (o == null) - { - writeAMFNull(); - return; - } - - if (!context.legacyExternalizable && o instanceof Externalizable) - { - writeCustomObject(o); - } - else if (o instanceof String || o instanceof Character) - { - String s = o.toString(); - writeAMFString(s); - } - else if (o instanceof Number) - { - if (o instanceof Integer || o instanceof Short || o instanceof Byte) - { - int i = ((Number)o).intValue(); - writeAMFInt(i); - } - else if (!context.legacyBigNumbers && - (o instanceof BigInteger || o instanceof BigDecimal)) - { - // Using double to write big numbers such as BigInteger or - // BigDecimal can result in information loss so we write - // them as String by default... - writeAMFString(o.toString()); - } - else - { - double d = ((Number)o).doubleValue(); - writeAMFDouble(d); - } - } - else if (o instanceof Boolean) - { - writeAMFBoolean(((Boolean)o).booleanValue()); - } - // We have a complex type... - else if (o instanceof Date) - { - writeAMFDate((Date)o); - } - else if (o instanceof Calendar) - { - writeAMFDate(((Calendar)o).getTime()); - } - else if (o instanceof Document) - { - if (context.legacyXMLDocument) - out.write(kXMLType); // Legacy flash.xml.XMLDocument Type - else - out.write(kAvmPlusXmlType); // New E4X XML Type - if (!byReference(o)) - { - String xml = documentToString(o); - if (isDebug) - trace.write(xml); - - writeAMFUTF(xml); - } - } - // If there is a proxy for this,write it as a custom object so the default - // behavior can be overriden. - else if (o instanceof Enum && PropertyProxyRegistry.getRegistry().getProxy(o.getClass()) == null) - { - Enum<?> enumValue = (Enum<?>)o; - writeAMFString(enumValue.name()); - } - else - { - // We have an Object or Array type... - Class cls = o.getClass(); - - if (context.legacyMap && o instanceof Map && !(o instanceof ASObject)) - { - writeMapAsECMAArray((Map)o); - } - else if (!context.legacyDictionary && o instanceof Dictionary) - { - writeDictionary((Dictionary)o); - } - else if (o instanceof Collection) - { - if (o instanceof List && context.preferVectors) - writeListAsTypedVector((List)o); - else if (context.legacyCollection) - writeCollection((Collection)o, null); - else - writeArrayCollection((Collection)o, null); - } - else if (cls.isArray()) - { - Class<?> componentType = cls.getComponentType(); - // Convert to vector if requested, except for character and byte arrays - if (context.preferVectors && - !(componentType.equals(Byte.class) || componentType.equals(byte.class))&& - !(componentType.equals(Character.class) || componentType.equals(char.class))) - writeArrayAsTypedVector(o, componentType); - else - writeAMFArray(o, componentType); - } - else - { - //Special Case: wrap RowSet in PageableRowSet for Serialization - if (o instanceof RowSet) - { - o = new PagedRowSet((RowSet)o, Integer.MAX_VALUE, false); - } - else if (context.legacyThrowable && o instanceof Throwable) - { - o = new StatusInfoProxy((Throwable)o); - } - - writeCustomObject(o); - } - } - } - - public void writeObjectTraits(TraitsInfo ti) throws IOException - { - String className = ti.getClassName(); - - if (isDebug) - { - if (ti.isExternalizable()) - trace.startExternalizableObject(className, getObjectTableSize()); - else - trace.startAMFObject(className, getObjectTableSize()); - } - - if (!byReference(ti)) - { - int count = 0; - List propertyNames = null; - boolean externalizable = ti.isExternalizable(); - - if (!externalizable) - { - propertyNames = ti.getProperties(); - if (propertyNames != null) - count = propertyNames.size(); - } - - boolean dynamic = ti.isDynamic(); - - writeUInt29(3 | (externalizable ? 4 : 0) | (dynamic ? 8 : 0) | (count << 4)); - writeStringWithoutType(className); - - if (!externalizable && propertyNames != null) - { - for (int i = 0; i < count; i++) - { - String propName = ti.getProperty(i); - writeStringWithoutType(propName); - } - } - } - } - - public void writeObjectProperty(String name, Object value) throws IOException - { - if (isDebug) - trace.namedElement(name); - increaseNestObjectLevel(); - writeObject(value); - decreaseNestObjectLevel(); - } - - public void writeObjectEnd() throws IOException - { - // No action required for AMF 3 - - if (isDebug) - trace.endAMFObject(); - } - - // - // AMF SPECIFIC SERIALIZATION IMPLEMENTATIONS - // - - /** - * - */ - protected void writeAMFBoolean(boolean b) throws IOException - { - if (isDebug) - trace.write(b); - - if (b) - out.write(kTrueType); - else - out.write(kFalseType); - } - - /** - * - */ - protected void writeAMFDate(Date d) throws IOException - { - out.write(kDateType); - - if (!byReference(d)) - { - if (isDebug) - trace.write(d); - - //Write out an invalid reference - writeUInt29(1); - - // Write the time as 64bit value in ms - out.writeDouble((double)d.getTime()); - } - } - - /** - * - */ - protected void writeAMFDouble(double d) throws IOException - { - if (isDebug) - trace.write(d); - - out.write(kDoubleType); - out.writeDouble(d); - } - - /** - * - */ - protected void writeAMFInt(int i) throws IOException - { - if (i >= INT28_MIN_VALUE && i <= INT28_MAX_VALUE) - { - if (isDebug) - trace.write(i); - - // We have to be careful when the MSB is set, as (value >> 3) will sign extend. - // We know there are only 29-bits of precision, so truncate. This requires - // similar care when reading an integer. - //i = ((i >> 3) & UINT29_MASK); - i = i & UINT29_MASK; // Mask is 2^29 - 1 - out.write(kIntegerType); - writeUInt29(i); - } - else - { - // Promote large int to a double - writeAMFDouble(i); - } - } - - protected void writeDictionary(Dictionary dictionary) throws IOException - { - out.write(kDictionaryType); - - if (byReference(dictionary)) - return; - - writeUInt29((dictionary.size() << 1) | 1); - writeAMFBoolean(false /*usingWeakKeys*/); - - if (isDebug) trace.startAMFDictionary(objectTable.size() - 1); - - Enumeration keys = dictionary.keys(); - while (keys.hasMoreElements()) - { - if (isDebug) trace.startDictionaryElement(); - Object key = keys.nextElement(); - increaseNestObjectLevel(); - writeObject(key); - decreaseNestObjectLevel(); - if (isDebug) trace.addDictionaryEquals(); - Object value = dictionary.get(key); - increaseNestObjectLevel(); - writeObject(value); - decreaseNestObjectLevel(); - } - - if (isDebug) - trace.endAMFDictionary(); - } - - protected void writeArrayAsTypedVector(Object array, Class<?> componentType) throws IOException - { - int vecType = kTypedVectorObject; - if (componentType.isPrimitive()) - { - if (int.class.equals(componentType)) - vecType = kTypedVectorInt; - else if (double.class.equals(componentType)) - vecType = kTypedVectorDouble; - } - else - { - if (Integer.class.equals(componentType)) - vecType = kTypedVectorInt; - else if (Double.class.equals(componentType)) - vecType = kTypedVectorDouble; - } - - out.write(vecType); - - if (byReference(array)) - return; - - int length = Array.getLength(array); - writeUInt29((length << 1) | 1); - writeBoolean(true /*fixed*/); - - switch (vecType) - { - case kTypedVectorInt: - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.INT); - - for (int i = 0; i < length; i++) - { - if (isDebug) - trace.arrayElement(i); - - Object element = Array.get(array, i); - int value = ((Integer)element).intValue(); - - if (isDebug) - trace.write(value); - - writeInt(value); - } - break; - case kTypedVectorDouble: - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.DOUBLE); - - for (int i = 0; i < length; i++) - { - if (isDebug) - trace.arrayElement(i); - - Object element = Array.get(array, i); - double value = ((Double)element).doubleValue(); - - if (isDebug) - trace.write(value); - - writeDouble(value); - } - break; - case kTypedVectorObject: - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.OBJECT); - - // TODO - I don't think this className is used properly on the client currently. - String className = componentType.getName(); - writeStringWithoutType(className); - - for (int i = 0; i < length; i++) - { - if (isDebug) - trace.arrayElement(i); - - Object element = Array.get(array, i); - increaseNestObjectLevel(); - writeObject(element); - decreaseNestObjectLevel(); - } - break; - default: - break; - } - - if (isDebug) - trace.endAMFVector(); - } - - protected void writeListAsTypedVector(List list) throws IOException - { - // Peek at the first three elements of the list to figure out what type - // of Vector it should be sent as. - int vecType = -1; - Class<?> initialElementClass = null; - int peekSize = Math.min(list.size(), 3); - for (int i = 0; i < peekSize; i++) - { - Object element = list.get(i); - if (i == 0) - { - initialElementClass = element != null? element.getClass() : null; - } - else - { - Class<?> currentElementClass = element != null? element.getClass() : null; - if (initialElementClass != currentElementClass) - { - vecType = kTypedVectorObject; - break; - } - } - } - - if (vecType == -1) - { - if (initialElementClass == Integer.class) - vecType = kTypedVectorInt; - else if (initialElementClass == Double.class) - vecType = kTypedVectorDouble; - else - vecType = kTypedVectorObject; - - } - - out.write(vecType); - - if (byReference(list)) - return; - - int length = list.size(); - writeUInt29((length << 1) | 1); - writeBoolean(false /*fixed*/); - - switch (vecType) - { - case kTypedVectorInt: - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.INT); - - for (int i = 0; i < length; i++) - { - if (isDebug) - trace.arrayElement(i); - - Object element = list.get(i); - int value = ((Integer)element).intValue(); - - if (isDebug) - trace.write(value); - - writeInt(value); - } - break; - case kTypedVectorDouble: - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.DOUBLE); - - for (int i = 0; i < length; i++) - { - if (isDebug) - trace.arrayElement(i); - - Object element = list.get(i); - double value = ((Double)element).doubleValue(); - - if (isDebug) - trace.write(value); - - writeDouble(value); - } - break; - case kTypedVectorObject: - if (isDebug) - trace.startAMFVector(objectTable.size() - 1, VectorType.OBJECT); - - // TODO - I don't think this className is used properly on the client currently. - String className = initialElementClass != null? initialElementClass.getName() : ""; - writeStringWithoutType(className); - - for (int i = 0; i < length; i++) - { - if (isDebug) - trace.arrayElement(i); - - Object element = list.get(i); - increaseNestObjectLevel(); - writeObject(element); - decreaseNestObjectLevel(); - } - break; - default: - break; - } - - if (isDebug) - trace.endAMFVector(); - } - - /** - * - */ - protected void writeMapAsECMAArray(Map map) throws IOException - { - out.write(kArrayType); - - if (!byReference(map)) - { - if (isDebug) - trace.startECMAArray(getObjectTableSize()); - - writeUInt29((0 << 1) | 1); - - Iterator it = map.keySet().iterator(); - while (it.hasNext()) - { - Object key = it.next(); - if (key != null) - { - String propName = key.toString(); - writeStringWithoutType(propName); - - if (isDebug) - trace.namedElement(propName); - - increaseNestObjectLevel(); - writeObject(map.get(key)); - decreaseNestObjectLevel(); - } - } - - writeStringWithoutType(EMPTY_STRING); - - if (isDebug) - trace.endAMFArray(); - } - } - - /** - * - */ - protected void writeAMFNull() throws IOException - { - if (isDebug) - trace.writeNull(); - - out.write(kNullType); - } - - /** - * - */ - protected void writeAMFString(String s) throws IOException - { - out.write(kStringType); - writeStringWithoutType(s); - - if (isDebug) - { - trace.writeString(s); - } - } - - /** - * - */ - protected void writeStringWithoutType(String s) throws IOException - { - if (s.length() == 0) - { - // don't create a reference for the empty string, - // as it's represented by the one byte value 1 - // len = 0, ((len << 1) | 1). - writeUInt29(1); - return; - } - - if (!byReference(s)) - { - writeAMFUTF(s); - return; - } - } - - /** - * - */ - protected void writeAMFArray(Object o, Class componentType) throws IOException - { - if (componentType.isPrimitive()) - { - writePrimitiveArray(o); - } - else if (componentType.equals(Byte.class)) - { - writeAMFByteArray((Byte[])o); - } - else if (componentType.equals(Character.class)) - { - writeCharArrayAsString((Character[])o); - } - else - { - writeObjectArray((Object[])o, null); - } - } - - /** - * - */ - protected void writeArrayCollection(Collection col, SerializationDescriptor desc) throws IOException - { - out.write(kObjectType); - - if (!byReference(col)) - { - ArrayCollection ac; - - if (col instanceof ArrayCollection) - { - ac = (ArrayCollection)col; - // TODO: QUESTION: Pete, ignoring the descriptor here... not sure if - // we should modify the user's AC as that could cause corruption? - } - else - { - // Wrap any Collection in an ArrayCollection - ac = new ArrayCollection(col); - if (desc != null) - ac.setDescriptor(desc); - } - - // Then wrap ArrayCollection in PropertyProxy for bean-like serialization - PropertyProxy proxy = PropertyProxyRegistry.getProxy(ac); - writePropertyProxy(proxy, ac); - } - } - - /** - * - */ - protected void writeCustomObject(Object o) throws IOException - { - PropertyProxy proxy = null; - - if (o instanceof PropertyProxy) - { - proxy = (PropertyProxy)o; - o = proxy.getDefaultInstance(); - - // The proxy may wrap a null default instance, if so, short circuit here. - if (o == null) - { - writeAMFNull(); - return; - } - - // HACK: Short circuit and unwrap if PropertyProxy is wrapping an Array - // or Collection or Map with legacyMap as true since we don't yet have - // the ability to proxy multiple AMF types. We write an AMF Array directly - // instead of an AMF Object... - else if (o instanceof Collection) - { - if (context.legacyCollection) - writeCollection((Collection)o, proxy.getDescriptor()); - else - writeArrayCollection((Collection)o, proxy.getDescriptor()); - return; - } - else if (o.getClass().isArray()) - { - writeObjectArray((Object[])o, proxy.getDescriptor()); - return; - } - else if (context.legacyMap && o instanceof Map && !(o instanceof ASObject)) - { - writeMapAsECMAArray((Map)o); - return; - } - } - - out.write(kObjectType); - - if (!byReference(o)) - { - if (proxy == null) - { - proxy = PropertyProxyRegistry.getProxyAndRegister(o); - } - - writePropertyProxy(proxy, o); - } - } - - /** - * - */ - protected void writePropertyProxy(PropertyProxy proxy, Object instance) throws IOException - { - /* - * At this point we substitute the instance we want to serialize. - */ - Object newInst = proxy.getInstanceToSerialize(instance); - if (newInst != instance) - { - // We can't use writeAMFNull here I think since we already added this object - // to the object table on the server side. The player won't have any way - // of knowing we have this reference mapped to null. - if (newInst == null) - throw new MessageException("PropertyProxy.getInstanceToSerialize class: " + proxy.getClass() + " returned null for instance class: " + instance.getClass().getName()); - - // Grab a new proxy if necessary for the new instance - proxy = PropertyProxyRegistry.getProxyAndRegister(newInst); - instance = newInst; - } - - List propertyNames = null; - boolean externalizable = proxy.isExternalizable(instance); - - if (!externalizable) - { - propertyNames = proxy.getPropertyNames(instance); - // filter write-only properties - if (proxy instanceof BeanProxy) - { - BeanProxy bp = (BeanProxy)proxy; - if (propertyNames != null && !propertyNames.isEmpty()) - { - List<String> propertiesToRemove = null; - for (int i = 0; i < propertyNames.size(); i++) - { - String propName = (String)propertyNames.get(i); - if (bp.isWriteOnly(instance, propName)) - { - if (propertiesToRemove == null) - propertiesToRemove = new ArrayList<String>(); - propertiesToRemove.add(propName); - } - } - if (propertiesToRemove != null) - propertyNames.removeAll(propertiesToRemove); - } - } - } - - - TraitsInfo ti = new TraitsInfo(proxy.getAlias(instance), proxy.isDynamic(), externalizable, propertyNames); - writeObjectTraits(ti); - - if (externalizable) - { - // Call user defined serialization - ((Externalizable)instance).writeExternal(this); - } - else if (propertyNames != null && !propertyNames.isEmpty()) - { - for (int i = 0; i < propertyNames.size(); i++) - { - String propName = (String)propertyNames.get(i); - Object value = proxy.getValue(instance, propName); - writeObjectProperty(propName, value); - } - } - - writeObjectEnd(); - } - - - /** - * Serialize an array of primitives. - * <p> - * Primitives include the following: - * boolean, char, double, float, long, int, short, byte - * </p> - * - * @param obj An array of primitives - * - */ - protected void writePrimitiveArray(Object obj) throws IOException - { - Class aType = obj.getClass().getComponentType(); - - if (aType.equals(Character.TYPE)) - { - //Treat char[] as a String - char[] c = (char[])obj; - writeCharArrayAsString(c); - } - else if (aType.equals(Byte.TYPE)) - { - writeAMFByteArray((byte[])obj); - } - else - { - out.write(kArrayType); - - if (!byReference(obj)) - { - if (aType.equals(Boolean.TYPE)) - { - boolean[] b = (boolean[])obj; - - // Write out an invalid reference, storing the length in the unused 28-bits. - writeUInt29((b.length << 1) | 1); - - // Send an empty string to imply no named keys - writeStringWithoutType(EMPTY_STRING); - - if (isDebug) - { - trace.startAMFArray(getObjectTableSize()); - - for (int i = 0; i < b.length; i++) - { - trace.arrayElement(i); - writeAMFBoolean(b[i]); - } - - trace.endAMFArray(); - } - else - { - for (int i = 0; i < b.length; i++) - { - writeAMFBoolean(b[i]); - } - } - } - else if (aType.equals(Integer.TYPE) || aType.equals(Short.TYPE)) - { - //We have a primitive number, either an int or short - //We write all of these as Integers... - int length = Array.getLength(obj); - - // Write out an invalid reference, storing the length in the unused 28-bits. - writeUInt29((length << 1) | 1); - // Send an empty string to imply no named keys - writeStringWithoutType(EMPTY_STRING); - - if (isDebug) - { - trace.startAMFArray(getObjectTableSize()); - - for (int i = 0; i < length; i++) - { - trace.arrayElement(i); - int v = Array.getInt(obj, i); - writeAMFInt(v); - } - - trace.endAMFArray(); - } - else - { - for (int i = 0; i < length; i++) - { - int v = Array.getInt(obj, i); - writeAMFInt(v); - } - } - } - else - { - //We have a primitive number, either a double, float, or long - //We write all of these as doubles... - int length = Array.getLength(obj); - - // Write out an invalid reference, storing the length in the unused 28-bits. - writeUInt29((length << 1) | 1); - // Send an empty string to imply no named keys - writeStringWithoutType(EMPTY_STRING); - - if (isDebug) - { - trace.startAMFArray(getObjectTableSize()); - - for (int i = 0; i < length; i++) - { - trace.arrayElement(i); - double v = Array.getDouble(obj, i); - writeAMFDouble(v); - } - - trace.endAMFArray(); - } - else - { - for (int i = 0; i < length; i++) - { - double v = Array.getDouble(obj, i); - writeAMFDouble(v); - } - } - } - } - } - } - - /** - * - */ - protected void writeAMFByteArray(byte[] ba) throws IOException - { - out.write(kByteArrayType); - - if (!byReference(ba)) - { - int length = ba.length; - - // Write out an invalid reference, storing the length in the unused 28-bits. - writeUInt29((length << 1) | 1); - - if (isDebug) - { - trace.startByteArray(getObjectTableSize(), length); - } - - out.write(ba, 0, length); - } - } - - /** - * - */ - protected void writeAMFByteArray(Byte[] ba) throws IOException - { - out.write(kByteArrayType); - - if (!byReference(ba)) - { - int length = ba.length; - - // Write out an invalid reference, storing the length in the unused 28-bits. - writeUInt29((length << 1) | 1); - - if (isDebug) - { - trace.startByteArray(getObjectTableSize(), length); - } - - for (int i = 0; i < ba.length; i++) - { - Byte b = ba[i]; - if (b == null) - out.write(0); - else - out.write(b.byteValue()); - } - } - } - - /** - * - */ - protected void writeCharArrayAsString(Character[] ca) throws IOException - { - int length = ca.length; - char[] chars = new char[length]; - - for (int i = 0; i < length; i++) - { - Character c = ca[i]; - if (c == null) - chars[i] = 0; - else - chars[i] = ca[i].charValue(); - } - writeCharArrayAsString(chars); - } - - /** - * - */ - protected void writeCharArrayAsString(char[] ca) throws IOException - { - String str = new String(ca); - writeAMFString(str); - } - - /** - * - */ - protected void writeObjectArray(Object[] values, SerializationDescriptor descriptor) throws IOException - { - out.write(kArrayType); - - if (!byReference(values)) - { - if (isDebug) - trace.startAMFArray(getObjectTableSize()); - - writeUInt29((values.length << 1) | 1); - - // Send an empty string to imply no named keys - writeStringWithoutType(EMPTY_STRING); - - for (int i = 0; i < values.length; ++i) - { - if (isDebug) - trace.arrayElement(i); - - Object item = values[i]; - if (item != null && descriptor != null && !(item instanceof String) - && !(item instanceof Number) && !(item instanceof Boolean) - && !(item instanceof Character)) - { - PropertyProxy proxy = PropertyProxyRegistry.getProxy(item); - proxy = (PropertyProxy)proxy.clone(); - proxy.setDescriptor(descriptor); - proxy.setDefaultInstance(item); - item = proxy; - } - increaseNestObjectLevel(); - writeObject(item); - decreaseNestObjectLevel(); - } - - if (isDebug) - trace.endAMFArray(); - } - } - - /** - * - */ - protected void writeCollection(Collection c, SerializationDescriptor descriptor) throws IOException - { - out.write(kArrayType); - - // Note: We process Collections independently of Object[] - // as we want the reference to be based on the actual - // Collection. - if (!byReference(c)) - { - if (isDebug) - trace.startAMFArray(getObjectTableSize()); - - writeUInt29((c.size() << 1) | 1); - - // Send an empty string to imply no named keys - writeStringWithoutType(EMPTY_STRING); - - Iterator it = c.iterator(); - int i = 0; - while (it.hasNext()) - { - if (isDebug) - trace.arrayElement(i); - - Object item = it.next(); - - if (item != null && descriptor != null && !(item instanceof String) - && !(item instanceof Number) && !(item instanceof Boolean) - && !(item instanceof Character)) - { - PropertyProxy proxy = PropertyProxyRegistry.getProxy(item); - proxy = (PropertyProxy)proxy.clone(); - proxy.setDescriptor(descriptor); - proxy.setDefaultInstance(item); - item = proxy; - } - increaseNestObjectLevel(); - writeObject(item); - decreaseNestObjectLevel(); - - i++; - } - - if (isDebug) - trace.endAMFArray(); - } - } - - /** - * - */ - protected void writeUInt29(int ref) throws IOException - { - // Represent smaller integers with fewer bytes using the most - // significant bit of each byte. The worst case uses 32-bits - // to represent a 29-bit number, which is what we would have - // done with no compression. - - // 0x00000000 - 0x0000007F : 0xxxxxxx - // 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx - // 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx - // 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx - // 0x40000000 - 0xFFFFFFFF : throw range exception - if (ref < 0x80) - { - // 0x00000000 - 0x0000007F : 0xxxxxxx - out.writeByte(ref); - } - else if (ref < 0x4000) - { - // 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx - out.writeByte(((ref >> 7) & 0x7F) | 0x80); - out.writeByte(ref & 0x7F); - - } - else if (ref < 0x200000) - { - // 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx - out.writeByte(((ref >> 14) & 0x7F) | 0x80); - out.writeByte(((ref >> 7) & 0x7F) | 0x80); - out.writeByte(ref & 0x7F); - - } - else if (ref < 0x40000000) - { - // 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx - out.writeByte(((ref >> 22) & 0x7F) | 0x80); - out.writeByte(((ref >> 15) & 0x7F) | 0x80); - out.writeByte(((ref >> 8) & 0x7F) | 0x80); - out.writeByte(ref & 0xFF); - - } - else - { - // 0x40000000 - 0xFFFFFFFF : throw range exception - throw new MessageException("Integer out of range: " + ref); - } - } - - /** - * - */ - public void writeAMFUTF(String s) throws IOException - { - int strlen = s.length(); - int utflen = 0; - int c, count = 0; - - char[] charr = getTempCharArray(strlen); - s.getChars(0, strlen, charr, 0); - - for (int i = 0; i < strlen; i++) - { - c = charr[i]; - if (c <= 0x007F) - { - utflen++; - } - else if (c > 0x07FF) - { - utflen += 3; - } - else - { - utflen += 2; - } - } - - writeUInt29((utflen << 1) | 1); - - byte[] bytearr = getTempByteArray(utflen); - - for (int i = 0; i < strlen; i++) - { - c = charr[i]; - if (c <= 0x007F) - { - bytearr[count++] = (byte)c; - } - else if (c > 0x07FF) - { - bytearr[count++] = (byte)(0xE0 | ((c >> 12) & 0x0F)); - bytearr[count++] = (byte)(0x80 | ((c >> 6) & 0x3F)); - bytearr[count++] = (byte)(0x80 | ((c >> 0) & 0x3F)); - } - else - { - bytearr[count++] = (byte)(0xC0 | ((c >> 6) & 0x1F)); - bytearr[count++] = (byte)(0x80 | ((c >> 0) & 0x3F)); - } - } - out.write(bytearr, 0, utflen); - } - - /** - * Attempts to serialize the object as a reference. - * If the object cannot be serialized as a reference, it is stored - * in the reference collection for potential future encounter. - * - * @return Success/failure indicator as to whether the object could be - * serialized as a reference. - * - */ - protected boolean byReference(Object o) throws IOException - { - if (objectTable != null && objectTable.containsKey(o)) - { - try - { - int refNum = objectTable.get(o).intValue(); - - if (isDebug) - trace.writeRef(refNum); - - writeUInt29(refNum << 1); - - return true; - } - catch (ClassCastException e) - { - throw new IOException("Object reference is not an Integer"); - } - } - - if (objectTable == null) - objectTable = new IdentityHashMap<Object, Integer>(64); - objectTable.put(o, Integer.valueOf(objectTable.size())); - return false; - } - - /** - * - */ - public void addObjectReference(Object o) throws IOException - { - byReference(o); - } - - /** - * - */ - protected boolean byReference(String s) throws IOException - { - if (stringTable != null && stringTable.containsKey(s)) - { - try - { - int refNum = stringTable.get(s).intValue(); - - writeUInt29(refNum << 1); - - if (isDebug && Trace.amf) - trace.writeStringRef(refNum); - return true; - } - catch (ClassCastException e) - { - throw new IOException("String reference is not an Integer"); - } - } - if (stringTable == null) - stringTable = new HashMap<String, Integer>(64); - stringTable.put(s, Integer.valueOf(stringTable.size())); - return false; - } - - /** - * - */ - protected boolean byReference(TraitsInfo ti) throws IOException - { - if (traitsTable != null && traitsTable.containsKey(ti)) - { - try - { - int refNum = traitsTable.get(ti).intValue(); - - writeUInt29((refNum << 2) | 1); - - if (isDebug && Trace.amf) - trace.writeTraitsInfoRef(refNum); - return true; - } - catch (ClassCastException e) - { - throw new IOException("TraitsInfo reference is not an Integer"); - } - } - if (traitsTable == null) - traitsTable = new HashMap<TraitsInfo, Integer>(10); - traitsTable.put(ti, Integer.valueOf(traitsTable.size())); - return false; - } - - protected int getObjectTableSize() - { - return objectTable != null? objectTable.size() - 1 : 0; - } -} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/core/src/flex/messaging/io/amf/Amf3Types.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/io/amf/Amf3Types.java b/core/src/flex/messaging/io/amf/Amf3Types.java deleted file mode 100644 index 72e1b82..0000000 --- a/core/src/flex/messaging/io/amf/Amf3Types.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package flex.messaging.io.amf; - -/** - * AMF3 type markers and constants for AVM+ Serialization. - * - * @see flex.messaging.io.amf.AmfTypes for AMF 0 Type Markers. - */ -public interface Amf3Types -{ - // AMF marker constants - int kUndefinedType = 0; - int kNullType = 1; - int kFalseType = 2; - int kTrueType = 3; - int kIntegerType = 4; - int kDoubleType = 5; - int kStringType = 6; - int kXMLType = 7; - int kDateType = 8; - int kArrayType = 9; - int kObjectType = 10; - int kAvmPlusXmlType = 11; - int kByteArrayType = 12; - int kTypedVectorInt = 13; - int kTypedVectorUint= 14; - int kTypedVectorDouble = 15; - int kTypedVectorObject = 16; - int kDictionaryType = 17; - - String EMPTY_STRING = ""; - - /** - * Internal use only. - * - */ - int UINT29_MASK = 0x1FFFFFFF; // 2^29 - 1 - - /** - * The maximum value for an <code>int</code> that will avoid promotion to an - * ActionScript Number when sent via AMF 3 is 2<sup>28</sup> - 1, or <code>0x0FFFFFFF</code>. - */ - int INT28_MAX_VALUE = 0x0FFFFFFF; // 2^28 - 1 - - /** - * The minimum value for an <code>int</code> that will avoid promotion to an - * ActionScript Number when sent via AMF 3 is -2<sup>28</sup> or <code>0xF0000000</code>. - */ - int INT28_MIN_VALUE = 0xF0000000; // -2^28 in 2^29 scheme -} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/core/src/flex/messaging/io/amf/AmfIO.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/io/amf/AmfIO.java b/core/src/flex/messaging/io/amf/AmfIO.java deleted file mode 100644 index 6336a4d..0000000 --- a/core/src/flex/messaging/io/amf/AmfIO.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package flex.messaging.io.amf; - -import flex.messaging.MessageException; -import flex.messaging.io.AbstractProxy; -import flex.messaging.io.SerializationContext; -import flex.messaging.io.SerializationException; -import flex.messaging.io.TypeMarshallingContext; - -/** - * Base class for Amf I/O. - * - */ -abstract class AmfIO -{ - protected final SerializationContext context; - /* - * DEBUG LOGGING. - */ - protected boolean isDebug; - protected AmfTrace trace; - - // Nest object level, how deep the object graph is right now - private int nestObjectLevel; - // Nest collection level, how deep the collection nest is right now, for example 3 dimensional matrix will reach level of 3 - private int nestCollectionLevel; - - - /* - * OPTIMIZATION. - */ - private char[] tempCharArray = null; - private byte[] tempByteArray = null; - - AmfIO(SerializationContext context) - { - this.context = context; - nestObjectLevel = 0; - nestCollectionLevel = 0; - } - - /** - * Turns on "trace" debugging for AMF responses. - * @param trace the trace object - */ - public void setDebugTrace(AmfTrace trace) - { - this.trace = trace; - isDebug = this.trace != null; - } - - /** - * Clear all object reference information so that the instance - * can be used to deserialize another data structure. - * - * Reset should be called before reading a top level object, - * such as a new header or a new body. - */ - public void reset() - { - nestObjectLevel = 0; - nestCollectionLevel = 0; - TypeMarshallingContext marshallingContext = TypeMarshallingContext.getTypeMarshallingContext(); - marshallingContext.reset(); - } - - /** - * Returns an existing array with a length of at least the specified - * capacity. This method is for optimization only. Do not use the array - * outside the context of this method and do not call this method again - * while the array is being used. - * @param capacity minimum length - * @return a character array - */ - final char[] getTempCharArray(int capacity) - { - char[] result = this.tempCharArray; - if ((result == null) || (result.length < capacity)) - { - result = new char[capacity * 2]; - tempCharArray = result; - } - return result; - } - - /** - * Returns an existing array with a length of at least the specified - * capacity. This method is for optimization only. Do not use the array - * outside the context of this method and do not call this method again - * while the array is being used. - * @param capacity minimum length - * @return a byte array - */ - final byte[] getTempByteArray(int capacity) - { - byte[] result = this.tempByteArray; - if ((result == null) || (result.length < capacity)) - { - result = new byte[capacity * 2]; - tempByteArray = result; - } - return result; - } - - protected void increaseNestObjectLevel() - { - nestObjectLevel++; - - if (nestObjectLevel > context.maxObjectNestLevel) - { - SerializationException se = new SerializationException(); - se.setMessage(10315, new Object[] {context.maxObjectNestLevel}); - throw se; - } - } - - protected void decreaseNestObjectLevel() - { - nestObjectLevel--; - } - - protected void increaseNestCollectionLevel() - { - nestCollectionLevel++; - if (nestCollectionLevel > context.maxCollectionNestLevel) - { - SerializationException se = new SerializationException(); - se.setMessage(10316, new Object[] {context.maxCollectionNestLevel}); - throw se; - } - } - - protected void decreaseNestCollectionLevel() - { - nestCollectionLevel--; - } - - public static boolean isCollectionClass(Object object) - { - if (object == null) - return false; - Class clazz = object.getClass(); - if (clazz.isArray()) - return true; - if (java.util.Collection.class.isAssignableFrom(clazz)) - return true; - if (java.util.Map.class.isAssignableFrom(clazz)) - return true; - if (flex.messaging.io.ArrayCollection.class.equals(clazz)) - return true; - return flex.messaging.io.ArrayList.class.equals(clazz); - } -}