001/*
002 * www.openamf.org
003 *
004 * Distributable under LGPL license.
005 * See terms of license at gnu.org.
006 */
007
008package org.granite.messaging.amf;
009
010import java.io.Serializable;
011import java.lang.reflect.Array;
012import java.util.ArrayList;
013import java.util.List;
014
015import flex.messaging.messages.Message;
016
017/**
018 * AMF Body
019 *
020 * @author Jason Calabrese <jasonc@missionvi.com>
021 * @author Pat Maddox <pergesu@users.sourceforge.net>
022 * @see AMF0Header
023 * @see AMF0Message
024 * @version $Revision: 1.19 $, $Date: 2003/09/20 01:05:24 $
025 */
026public class AMF0Body implements Serializable {
027
028    private static final long serialVersionUID = 1L;
029
030    protected String target;
031    protected String serviceName;
032    protected String serviceMethodName;
033    protected String response;
034    protected Object value;
035    protected byte type;
036    /**
037     * Unknow object type
038     */
039    public static final byte DATA_TYPE_UNKNOWN = -1;
040    /**
041     * Number object type
042     */
043    public static final byte DATA_TYPE_NUMBER = 0;
044    /**
045     * Boolean object type
046     */
047    public static final byte DATA_TYPE_BOOLEAN = 1;
048    /**
049     * String object type
050     */
051    public static final byte DATA_TYPE_STRING = 2;
052    /**
053     * Object object type
054     */
055    public static final byte DATA_TYPE_OBJECT = 3;
056    /**
057     * Movie clip object type
058     */
059    public static final byte DATA_TYPE_MOVIE_CLIP = 4;
060    /**
061     * NULL object type
062     */
063    public static final byte DATA_TYPE_NULL = 5;
064    /**
065     * Undefined object type
066     */
067    public static final byte DATA_TYPE_UNDEFINED = 6;
068    /**
069     * Reference object type
070     */
071    public static final byte DATA_TYPE_REFERENCE_OBJECT = 7;
072    /**
073     * Mixed Array Object type
074     */
075    public static final byte DATA_TYPE_MIXED_ARRAY = 8;
076    /**
077     * Object end type
078     */
079    public static final byte DATA_TYPE_OBJECT_END = 9;
080    /**
081     * Array Object type
082     */
083    public static final byte DATA_TYPE_ARRAY = 10;
084    /**
085     * Date object type
086     */
087    public static final byte DATA_TYPE_DATE = 11;
088    /**
089     * Long String object type
090     */
091    public static final byte DATA_TYPE_LONG_STRING = 12;
092    /**
093     * General Object type
094     */
095    public static final byte DATA_TYPE_AS_OBJECT = 13;
096    /**
097     * RecordSet object type
098     */
099    public static final byte DATA_TYPE_RECORDSET = 14;
100    /**
101     * XML Document object type
102     */
103    public static final byte DATA_TYPE_XML = 15;
104    /**
105     * Custom class object type
106     */
107    public static final byte DATA_TYPE_CUSTOM_CLASS = 16;
108    /**
109     * AMF3 data
110     */
111    public static final byte DATA_TYPE_AMF3_OBJECT = 17;
112
113    /**
114     * AMF body with unknown type
115     *
116     * @param target
117     * @param response
118     * @param value
119     */
120    public AMF0Body(String target, String response, Object value) {
121        this(target, response, value, DATA_TYPE_UNKNOWN);
122    }
123
124    /**
125     * AMF Body constructor
126     *
127     * @param target
128     * @param response
129     * @param value
130     * @param type
131     */
132    public AMF0Body(String target, String response, Object value, byte type) {
133        this.response = response;
134        this.value = value;
135        this.type = type;
136        setTarget(target);
137    }
138
139    public String getTarget() {
140        return target;
141    }
142
143    public void setTarget(String target) {
144        this.target = target;
145        int dotIndex = target.lastIndexOf('.');
146        if (dotIndex > 0) {
147            this.serviceName = target.substring(0, dotIndex);
148            this.serviceMethodName = target.substring(dotIndex + 1);
149        }
150    }
151
152    public String getServiceName() {
153        return serviceName;
154    }
155
156    public String getServiceMethodName() {
157        return serviceMethodName;
158    }
159
160    public String getResponse() {
161        return response;
162    }
163
164    public void setResponse(String response) {
165        this.response = response;
166    }
167
168    public boolean isFirstBody() {
169        return "/1".equals(response);
170    }
171
172    public int getBodyIndex() {
173        if (response != null && response.length() > 1) {
174            try {
175                return Integer.parseInt(response.substring(1));
176            } catch (Exception e) {
177            }
178        }
179        return 0; // response starts with 1.
180    }
181
182    public Object getValue() {
183        return value;
184    }
185
186    public void setValue(Object value) {
187        this.value = value;
188    }
189    /**
190     * Returns object type
191     *
192     * @return the object type.
193     */
194    public byte getType() {
195        return type;
196    }
197    /**
198     * Sets object type
199     *
200     * @param type
201     */
202    public void setType(byte type) {
203        this.type = type;
204    }
205    /**
206     * Returns String description of object type
207     *
208     * @param type object type
209     * @return the object type description
210     */
211    public static String getObjectTypeDescription(byte type) {
212        switch (type) {
213            case DATA_TYPE_UNKNOWN:
214                return "UNKNOWN";
215            case DATA_TYPE_NUMBER:
216                return "NUMBER";
217            case DATA_TYPE_BOOLEAN:
218                return "BOOLEAN";
219            case DATA_TYPE_STRING:
220                return "STRING";
221            case DATA_TYPE_OBJECT:
222                return "OBJECT";
223            case DATA_TYPE_MOVIE_CLIP:
224                return "MOVIECLIP";
225            case DATA_TYPE_NULL:
226                return "NULL";
227            case DATA_TYPE_UNDEFINED:
228                return "UNDEFINED";
229            case DATA_TYPE_REFERENCE_OBJECT:
230                return "REFERENCE";
231            case DATA_TYPE_MIXED_ARRAY:
232                return "MIXED_ARRAY";
233            case DATA_TYPE_OBJECT_END:
234                return "OBJECT_END";
235            case DATA_TYPE_ARRAY:
236                return "ARRAY";
237            case DATA_TYPE_DATE:
238                return "DATE";
239            case DATA_TYPE_LONG_STRING:
240                return "LONG_STRING";
241            case DATA_TYPE_AS_OBJECT:
242                return "AS_OBJECT";
243            case DATA_TYPE_RECORDSET:
244                return "RECORDSET";
245            case DATA_TYPE_XML:
246                return "XML";
247            case DATA_TYPE_CUSTOM_CLASS:
248                return "CUSTOM_CLASS";
249            case DATA_TYPE_AMF3_OBJECT:
250                return "AMF3_OBJECT";
251            default:
252                return "UNKNOWN: 0x" + Integer.toBinaryString(type);
253        }
254    }
255
256    @Override
257    public String toString() {
258        return toString("");
259    }
260
261    public String toString(String indent) {
262        return (new StringBuffer(1024)
263            .append('\n').append(indent).append(AMF0Body.class.getName()).append(" {")
264            .append('\n').append(indent).append("  target = ").append(getTarget())
265            .append('\n').append(indent).append("  serviceName = ").append(getServiceName())
266            .append('\n').append(indent).append("  serviceMethodName = ").append(getServiceMethodName())
267            .append('\n').append(indent).append("  response = ").append(getResponse())
268            .append('\n').append(indent).append("  type = ").append(getObjectTypeDescription(type))
269            .append('\n').append(indent).append("  value = ").append(printValue(value, indent + "  "))
270            .append('\n').append(indent).append('}')
271            .toString()
272        );
273    }
274
275    private static String printValue(Object value, String indent) {
276
277        if (value == null)
278            return "null";
279
280        if (value instanceof AMF3Object)
281            return ((AMF3Object)value).toString(indent);
282        if (value instanceof Message)
283            return ((Message)value).toString(indent);
284
285        if (value.getClass().isArray()) {
286            final int length = Array.getLength(value);
287            List<Object> list = new ArrayList<Object>(length);
288            for (int i = 0; i < length; i++)
289                list.add(Array.get(value, i));
290            value = list;
291        }
292
293        if (value instanceof List<?>) {
294            List<?> list = (List<?>)value;
295
296            StringBuilder sb = new StringBuilder(512);
297
298            final String innerIndent = indent + "  ";
299            sb.append('[');
300            for (int i = 0; i < list.size(); i++) {
301                if (i > 0)
302                    sb.append(',');
303                sb.append('\n').append(indent).append("  ").append(printValue(list.get(i), innerIndent));
304            }
305            if (list.size() > 0)
306                sb.append('\n').append(indent);
307            sb.append(']');
308
309            return sb.toString();
310        }
311
312        return value.toString();
313    }
314}