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