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 package org.granite.messaging.amf.io;
023
024 import java.io.DataOutputStream;
025 import java.io.Externalizable;
026 import java.io.IOException;
027 import java.io.ObjectOutput;
028 import java.io.OutputStream;
029 import java.lang.reflect.Array;
030 import java.math.BigDecimal;
031 import java.math.BigInteger;
032 import java.util.Calendar;
033 import java.util.Collection;
034 import java.util.Date;
035 import java.util.HashMap;
036 import java.util.IdentityHashMap;
037 import java.util.Map;
038
039 import org.granite.config.flex.Channel;
040 import org.granite.context.GraniteContext;
041 import org.granite.logging.Logger;
042 import org.granite.messaging.amf.AMF3Constants;
043 import org.granite.messaging.amf.io.convert.Converters;
044 import org.granite.messaging.amf.io.util.ClassGetter;
045 import org.granite.messaging.amf.io.util.DefaultJavaClassDescriptor;
046 import org.granite.messaging.amf.io.util.IndexedJavaClassDescriptor;
047 import org.granite.messaging.amf.io.util.JavaClassDescriptor;
048 import org.granite.messaging.amf.io.util.externalizer.Externalizer;
049 import org.granite.messaging.amf.types.AMFDictionaryValue;
050 import org.granite.messaging.amf.types.AMFSpecialValue;
051 import org.granite.messaging.amf.types.AMFSpecialValueFactory;
052 import org.granite.messaging.amf.types.AMFVectorIntValue;
053 import org.granite.messaging.amf.types.AMFVectorNumberValue;
054 import org.granite.messaging.amf.types.AMFVectorObjectValue;
055 import org.granite.messaging.amf.types.AMFVectorUintValue;
056 import org.granite.util.TypeUtil;
057 import org.granite.util.XMLUtil;
058 import org.granite.util.XMLUtilFactory;
059 import org.w3c.dom.Document;
060
061 import flex.messaging.io.ArrayCollection;
062
063 /**
064 * @author Franck WOLFF
065 */
066 public class AMF3Serializer extends DataOutputStream implements ObjectOutput, AMF3Constants {
067
068 ///////////////////////////////////////////////////////////////////////////
069 // Fields.
070
071 protected static final Logger log = Logger.getLogger(AMF3Serializer.class);
072 protected static final Logger logMore = Logger.getLogger(AMF3Serializer.class.getName() + "_MORE");
073
074 protected final Map<String, Integer> storedStrings = new HashMap<String, Integer>();
075 protected final Map<Object, Integer> storedObjects = new IdentityHashMap<Object, Integer>();
076 protected final Map<String, IndexedJavaClassDescriptor> storedClassDescriptors
077 = new HashMap<String, IndexedJavaClassDescriptor>();
078
079 protected final GraniteContext context = GraniteContext.getCurrentInstance();
080 protected final Converters converters = context.getGraniteConfig().getConverters();
081
082 protected final boolean externalizeLong
083 = (context.getGraniteConfig().getExternalizer(Long.class.getName()) != null);
084 protected final boolean externalizeBigInteger
085 = (context.getGraniteConfig().getExternalizer(BigInteger.class.getName()) != null);
086 protected final boolean externalizeBigDecimal
087 = (context.getGraniteConfig().getExternalizer(BigDecimal.class.getName()) != null);
088
089 protected final XMLUtil xmlUtil = XMLUtilFactory.getXMLUtil();
090
091 // TODO: allow aliaser configuration in granite-config.xml
092 protected final AMFSpecialValueFactory specialValueFactory = new AMFSpecialValueFactory();
093
094 protected final boolean debug = log.isDebugEnabled();
095 protected final boolean debugMore = logMore.isDebugEnabled();
096
097 protected Channel channel = null;
098
099 ///////////////////////////////////////////////////////////////////////////
100 // Constructor.
101
102 public AMF3Serializer(OutputStream out) {
103 super(out);
104
105 if (debugMore) logMore.debug("new AMF3Serializer(out=%s)", out);
106 }
107
108 ///////////////////////////////////////////////////////////////////////////
109 // ObjectOutput implementation.
110
111 public void writeObject(Object o) throws IOException {
112 if (debugMore) logMore.debug("writeObject(o=%s)", o);
113
114 try {
115 if (o == null)
116 write(AMF3_NULL);
117 else if (o instanceof AMFSpecialValue)
118 writeAMF3SpecialValue((AMFSpecialValue<?>)o);
119 else if (!(o instanceof Externalizable)) {
120
121 if (converters.hasReverters())
122 o = converters.revert(o);
123
124 if (o == null)
125 write(AMF3_NULL);
126 else if (o instanceof String || o instanceof Character)
127 writeAMF3String(o.toString());
128 else if (o instanceof Boolean)
129 write(((Boolean)o).booleanValue() ? AMF3_BOOLEAN_TRUE : AMF3_BOOLEAN_FALSE);
130 else if (o instanceof Number) {
131 if (o instanceof Integer || o instanceof Short || o instanceof Byte)
132 writeAMF3Integer(((Number)o).intValue());
133 else if (externalizeLong && o instanceof Long)
134 writeAMF3Object(o);
135 else if (externalizeBigInteger && o instanceof BigInteger)
136 writeAMF3Object(o);
137 else if (externalizeBigDecimal && o instanceof BigDecimal)
138 writeAMF3Object(o);
139 else
140 writeAMF3Number(((Number)o).doubleValue());
141 }
142 else if (o instanceof Date)
143 writeAMF3Date((Date)o);
144 else if (o instanceof Calendar)
145 writeAMF3Date(((Calendar)o).getTime());
146 else if (o instanceof Document)
147 writeAMF3Xml((Document)o);
148 else if (o instanceof Collection<?>)
149 writeAMF3Collection((Collection<?>)o);
150 else if (o.getClass().isArray()) {
151 if (o.getClass().getComponentType() == Byte.TYPE)
152 writeAMF3ByteArray((byte[])o);
153 else
154 writeAMF3Array(o);
155 }
156 else
157 writeAMF3Object(o);
158 }
159 else
160 writeAMF3Object(o);
161 }
162 catch (IOException e) {
163 throw e;
164 }
165 catch (Exception e) {
166 throw new AMF3SerializationException(e);
167 }
168 }
169
170 ///////////////////////////////////////////////////////////////////////////
171 // AMF3 serialization.
172
173 protected void writeAMF3SpecialValue(AMFSpecialValue<?> value) throws IOException {
174 if (debugMore) logMore.debug("writeAMF3SpecialValue(value=%s)", value);
175
176 switch (value.type) {
177 case AMF3_DICTIONARY:
178 writeAMF3Dictionary((AMFDictionaryValue)value);
179 break;
180 case AMF3_VECTOR_INT:
181 writeAMF3VectorInt((AMFVectorIntValue)value);
182 break;
183 case AMF3_VECTOR_NUMBER:
184 writeAMF3VectorNumber((AMFVectorNumberValue)value);
185 break;
186 case AMF3_VECTOR_UINT:
187 writeAMF3VectorUint((AMFVectorUintValue)value);
188 break;
189 case AMF3_VECTOR_OBJECT:
190 writeAMF3VectorObject((AMFVectorObjectValue)value);
191 break;
192 default:
193 throw new RuntimeException("Unsupported AMF special value: " + value);
194 }
195 }
196
197 protected void writeAMF3VectorObject(AMFVectorObjectValue value) throws IOException {
198 if (debugMore) logMore.debug("writeAMF3VectorObject(value=%s)", value);
199
200 write(AMF3_VECTOR_OBJECT);
201
202 Object o = value.value;
203
204 int index = indexOfStoredObjects(o);
205 if (index >= 0)
206 writeAMF3IntegerData(index << 1);
207 else {
208 addToStoredObjects(o);
209
210 int length = getArrayOrCollectionLength(o);
211 writeAMF3IntegerData(length << 1 | 0x01);
212 write(value.fixed ? 0x01 : 0x00);
213 writeAMF3StringData(value.type);
214
215 if (o.getClass().isArray()) {
216 for (int i = 0; i < length; i++)
217 writeObject(Array.get(o, i));
218 }
219 else {
220 for (Object item : (Collection<?>)o)
221 writeObject(item);
222 }
223 }
224 }
225
226 protected void writeAMF3VectorInt(AMFVectorIntValue value) throws IOException {
227 if (debugMore) logMore.debug("writeAMF3VectorInt(value=%s)", value);
228
229 write(AMF3_VECTOR_INT);
230
231 Object o = value.value;
232
233 int index = indexOfStoredObjects(o);
234 if (index >= 0)
235 writeAMF3IntegerData(index << 1);
236 else {
237 addToStoredObjects(o);
238
239 int length = getArrayOrCollectionLength(o);
240 writeAMF3IntegerData(length << 1 | 0x01);
241 write(value.fixed ? 0x01 : 0x00);
242
243 if (o.getClass().isArray()) {
244 for (int i = 0; i < length; i++)
245 writeInt(((Number)Array.get(o, i)).intValue());
246 }
247 else {
248 for (Object item : (Collection<?>)o)
249 writeInt(((Number)item).intValue());
250 }
251 }
252 }
253
254 protected void writeAMF3VectorNumber(AMFVectorNumberValue value) throws IOException {
255 if (debugMore) logMore.debug("writeAMF3VectorNumber(value=%s)", value);
256
257 write(AMF3_VECTOR_NUMBER);
258
259 Object o = value.value;
260
261 int index = indexOfStoredObjects(o);
262 if (index >= 0)
263 writeAMF3IntegerData(index << 1);
264 else {
265 addToStoredObjects(o);
266
267 int length = getArrayOrCollectionLength(o);
268 writeAMF3IntegerData(length << 1 | 0x01);
269 write(value.fixed ? 0x01 : 0x00);
270
271 if (o.getClass().isArray()) {
272 for (int i = 0; i < length; i++)
273 writeDouble(((Number)Array.get(o, i)).doubleValue());
274 }
275 else {
276 for (Object item : (Collection<?>)o)
277 writeDouble(((Number)item).doubleValue());
278 }
279 }
280 }
281
282 protected void writeAMF3VectorUint(AMFVectorUintValue value) throws IOException {
283 if (debugMore) logMore.debug("writeAMF3VectorUint(value=%s)", value);
284
285 write(AMF3_VECTOR_UINT);
286
287 Object o = value.value;
288
289 int index = indexOfStoredObjects(o);
290 if (index >= 0)
291 writeAMF3IntegerData(index << 1);
292 else {
293 addToStoredObjects(o);
294
295 int length = getArrayOrCollectionLength(o);
296 writeAMF3IntegerData(length << 1 | 0x01);
297 write(value.fixed ? 0x01 : 0x00);
298
299 if (o.getClass().isArray()) {
300 for (int i = 0; i < length; i++)
301 writeInt(((Number)Array.get(o, i)).intValue());
302 }
303 else {
304 for (Object item : (Collection<?>)o)
305 writeInt(((Number)item).intValue());
306 }
307 }
308 }
309
310 protected void writeAMF3Dictionary(AMFDictionaryValue value) throws IOException {
311 if (debugMore) logMore.debug("writeAMFDictionary(value=%s)", value);
312
313 write(AMF3_DICTIONARY);
314
315 Map<?, ?> o = value.value;
316
317 int index = indexOfStoredObjects(o);
318 if (index >= 0)
319 writeAMF3IntegerData(index << 1);
320 else {
321 addToStoredObjects(o);
322
323 int length = o.size();
324 writeAMF3IntegerData(length << 1 | 0x01);
325 write(value.weakKeys ? 0x01 : 0x00);
326
327 for (Map.Entry<?, ?> entry : o.entrySet()) {
328 writeObject(entry.getKey());
329 writeObject(entry.getValue());
330 }
331 }
332 }
333
334 protected int getArrayOrCollectionLength(Object o) {
335 if (o.getClass().isArray())
336 return Array.getLength(o);
337 return ((Collection<?>)o).size();
338 }
339
340 protected void writeAMF3Integer(int i) throws IOException {
341 if (debugMore) logMore.debug("writeAMF3Integer(i=%d)", i);
342
343 if (i < AMF3_INTEGER_MIN || i > AMF3_INTEGER_MAX) {
344 if (debugMore) logMore.debug("writeAMF3Integer() - %d is out of AMF3 int range, writing it as a Number", i);
345 writeAMF3Number(i);
346 }
347 else {
348 write(AMF3_INTEGER);
349 writeAMF3IntegerData(i);
350 }
351 }
352
353 protected void writeAMF3IntegerData(int i) throws IOException {
354 if (debugMore) logMore.debug("writeAMF3IntegerData(i=%d)", i);
355
356 if (i < AMF3_INTEGER_MIN || i > AMF3_INTEGER_MAX)
357 throw new IllegalArgumentException("Integer out of range: " + i);
358
359 if (i < 0 || i >= 0x200000) {
360 write(((i >> 22) & 0x7F) | 0x80);
361 write(((i >> 15) & 0x7F) | 0x80);
362 write(((i >> 8) & 0x7F) | 0x80);
363 write(i & 0xFF);
364 }
365 else {
366 if (i >= 0x4000)
367 write(((i >> 14) & 0x7F) | 0x80);
368 if (i >= 0x80)
369 write(((i >> 7) & 0x7F) | 0x80);
370 write(i & 0x7F);
371 }
372 }
373
374 protected void writeAMF3Number(double d) throws IOException {
375 if (debugMore) logMore.debug("writeAMF3Number(d=%f)", d);
376
377 write(AMF3_NUMBER);
378 writeDouble(d);
379 }
380
381 protected void writeAMF3String(String s) throws IOException {
382 if (debugMore) logMore.debug("writeAMF3String(s=%s)", s);
383
384 write(AMF3_STRING);
385 writeAMF3StringData(s);
386 }
387
388 protected void writeAMF3StringData(String s) throws IOException {
389 if (debugMore) logMore.debug("writeAMF3StringData(s=%s)", s);
390
391 if (s.length() == 0) {
392 write(0x01);
393 return;
394 }
395
396 int index = indexOfStoredStrings(s);
397
398 if (index >= 0)
399 writeAMF3IntegerData(index << 1);
400 else {
401 addToStoredStrings(s);
402
403 final int sLength = s.length();
404
405 // Compute and write modified UTF-8 string length.
406 int uLength = 0;
407 for (int i = 0; i < sLength; i++) {
408 int c = s.charAt(i);
409 if ((c >= 0x0001) && (c <= 0x007F))
410 uLength++;
411 else if (c > 0x07FF)
412 uLength += 3;
413 else
414 uLength += 2;
415 }
416 writeAMF3IntegerData((uLength << 1) | 0x01);
417
418 // Write modified UTF-8 bytes.
419 for (int i = 0; i < sLength; i++) {
420 int c = s.charAt(i);
421 if ((c >= 0x0001) && (c <= 0x007F)) {
422 write(c);
423 }
424 else if (c > 0x07FF) {
425 write(0xE0 | ((c >> 12) & 0x0F));
426 write(0x80 | ((c >> 6) & 0x3F));
427 write(0x80 | ((c >> 0) & 0x3F));
428 }
429 else {
430 write(0xC0 | ((c >> 6) & 0x1F));
431 write(0x80 | ((c >> 0) & 0x3F));
432 }
433 }
434 }
435 }
436
437 protected void writeAMF3Xml(Document doc) throws IOException {
438 if (debugMore) logMore.debug("writeAMF3Xml(doc=%s)", doc);
439
440 byte xmlType = AMF3_XMLSTRING;
441 Channel channel = getChannel();
442 if (channel != null && channel.isLegacyXmlSerialization())
443 xmlType = AMF3_XML;
444 write(xmlType);
445
446 int index = indexOfStoredObjects(doc);
447 if (index >= 0)
448 writeAMF3IntegerData(index << 1);
449 else {
450 addToStoredObjects(doc);
451
452 byte[] bytes = xmlUtil.toString(doc).getBytes("UTF-8");
453 writeAMF3IntegerData((bytes.length << 1) | 0x01);
454 write(bytes);
455 }
456 }
457
458 protected void writeAMF3Date(Date date) throws IOException {
459 if (debugMore) logMore.debug("writeAMF3Date(date=%s)", date);
460
461 write(AMF3_DATE);
462
463 int index = indexOfStoredObjects(date);
464 if (index >= 0)
465 writeAMF3IntegerData(index << 1);
466 else {
467 addToStoredObjects(date);
468 writeAMF3IntegerData(0x01);
469 writeDouble(date.getTime());
470 }
471 }
472
473 protected void writeAMF3Array(Object array) throws IOException {
474 if (debugMore) logMore.debug("writeAMF3Array(array=%s)", array);
475
476 write(AMF3_ARRAY);
477
478 int index = indexOfStoredObjects(array);
479 if (index >= 0)
480 writeAMF3IntegerData(index << 1);
481 else {
482 addToStoredObjects(array);
483
484 int length = Array.getLength(array);
485 writeAMF3IntegerData(length << 1 | 0x01);
486 write(0x01);
487 for (int i = 0; i < length; i++)
488 writeObject(Array.get(array, i));
489 }
490 }
491
492 protected void writeAMF3ByteArray(byte[] bytes) throws IOException {
493 if (debugMore) logMore.debug("writeAMF3ByteArray(bytes=%s)", bytes);
494
495 write(AMF3_BYTEARRAY);
496
497 int index = indexOfStoredObjects(bytes);
498 if (index >= 0)
499 writeAMF3IntegerData(index << 1);
500 else {
501 addToStoredObjects(bytes);
502
503 writeAMF3IntegerData(bytes.length << 1 | 0x01);
504 //write(bytes);
505
506 for (int i = 0; i < bytes.length; i++)
507 out.write(bytes[i]);
508 }
509 }
510
511 protected void writeAMF3Collection(Collection<?> c) throws IOException {
512 if (debugMore) logMore.debug("writeAMF3Collection(c=%s)", c);
513
514 Channel channel = getChannel();
515 if (channel != null && channel.isLegacyCollectionSerialization())
516 writeAMF3Array(c.toArray());
517 else {
518 ArrayCollection ac = (c instanceof ArrayCollection ? (ArrayCollection)c : new ArrayCollection(c));
519 writeAMF3Object(ac);
520 }
521 }
522
523 protected void writeAMF3Object(Object o) throws IOException {
524 if (debug) log.debug("writeAMF3Object(o=%s)...", o);
525
526 write(AMF3_OBJECT);
527
528 int index = indexOfStoredObjects(o);
529 if (index >= 0)
530 writeAMF3IntegerData(index << 1);
531 else {
532 addToStoredObjects(o);
533
534 ClassGetter classGetter = context.getGraniteConfig().getClassGetter();
535 if (debug) log.debug("writeAMF3Object() - classGetter=%s", classGetter);
536
537 Class<?> oClass = classGetter.getClass(o);
538 if (debug) log.debug("writeAMF3Object() - oClass=%s", oClass);
539
540 JavaClassDescriptor desc = null;
541
542 // write class description.
543 IndexedJavaClassDescriptor iDesc = getFromStoredClassDescriptors(oClass);
544 if (iDesc != null) {
545 desc = iDesc.getDescriptor();
546 writeAMF3IntegerData(iDesc.getIndex() << 2 | 0x01);
547 }
548 else {
549 iDesc = addToStoredClassDescriptors(oClass);
550 desc = iDesc.getDescriptor();
551
552 writeAMF3IntegerData((desc.getPropertiesCount() << 4) | (desc.getEncoding() << 2) | 0x03);
553 writeAMF3StringData(desc.getName());
554
555 for (int i = 0; i < desc.getPropertiesCount(); i++)
556 writeAMF3StringData(desc.getPropertyName(i));
557 }
558 if (debug) log.debug("writeAMF3Object() - desc=%s", desc);
559
560 // write object content.
561 if (desc.isExternalizable()) {
562 Externalizer externalizer = desc.getExternalizer();
563
564 if (externalizer != null) {
565 if (debug) log.debug("writeAMF3Object() - using externalizer=%s", externalizer);
566 try {
567 externalizer.writeExternal(o, this);
568 }
569 catch (IOException e) {
570 throw e;
571 }
572 catch (Exception e) {
573 throw new RuntimeException("Could not externalize object: " + o, e);
574 }
575 }
576 else {
577 if (debug) log.debug("writeAMF3Object() - legacy Externalizable=%s", o);
578 ((Externalizable)o).writeExternal(this);
579 }
580 }
581 else {
582 if (debug) log.debug("writeAMF3Object() - writing defined properties...");
583 for (int i = 0; i < desc.getPropertiesCount(); i++) {
584 Object obj = desc.getPropertyValue(i, o);
585 if (debug) log.debug("writeAMF3Object() - writing defined property: %s=%s", desc.getPropertyName(i), obj);
586 writeObject(specialValueFactory.createSpecialValue(desc.getProperty(i), obj));
587 }
588
589 if (desc.isDynamic()) {
590 if (debug) log.debug("writeAMF3Object() - writing dynamic properties...");
591 Map<?, ?> oMap = (Map<?, ?>)o;
592 for (Map.Entry<?, ?> entry : oMap.entrySet()) {
593 Object key = entry.getKey();
594 if (key != null) {
595 String propertyName = key.toString();
596 if (propertyName.length() > 0) {
597 if (debug) log.debug(
598 "writeAMF3Object() - writing dynamic property: %s=%s",
599 propertyName, entry.getValue()
600 );
601 writeAMF3StringData(propertyName);
602 writeObject(entry.getValue());
603 }
604 }
605 }
606 writeAMF3StringData("");
607 }
608 }
609 }
610
611 if (debug) log.debug("writeAMF3Object(o=%s) - Done", o);
612 }
613
614 ///////////////////////////////////////////////////////////////////////////
615 // Cached objects methods.
616
617 protected void addToStoredStrings(String s) {
618 if (!storedStrings.containsKey(s)) {
619 Integer index = Integer.valueOf(storedStrings.size());
620 if (debug) log.debug("addToStoredStrings(s=%s) at index=%d", s, index);
621 storedStrings.put(s, index);
622 }
623 }
624
625 protected int indexOfStoredStrings(String s) {
626 Integer index = storedStrings.get(s);
627 if (debug) log.debug("indexOfStoredStrings(s=%s) -> %d", s, (index != null ? index : -1));
628 return (index != null ? index : -1);
629 }
630
631 protected void addToStoredObjects(Object o) {
632 if (o != null && !storedObjects.containsKey(o)) {
633 Integer index = Integer.valueOf(storedObjects.size());
634 if (debug) log.debug("addToStoredObjects(o=%s) at index=%d", o, index);
635 storedObjects.put(o, index);
636 }
637 }
638
639 protected int indexOfStoredObjects(Object o) {
640 Integer index = storedObjects.get(o);
641 if (debug) log.debug("indexOfStoredObjects(o=%s) -> %d", o, (index != null ? index : -1));
642 return (index != null ? index : -1);
643 }
644
645 protected IndexedJavaClassDescriptor addToStoredClassDescriptors(Class<?> clazz) {
646 final String name = JavaClassDescriptor.getClassName(clazz);
647
648 if (debug) log.debug("addToStoredClassDescriptors(clazz=%s)", clazz);
649
650 if (storedClassDescriptors.containsKey(name))
651 throw new RuntimeException(
652 "Descriptor of \"" + name + "\" is already stored at index: " +
653 getFromStoredClassDescriptors(clazz).getIndex()
654 );
655
656 // find custom class descriptor and instantiate if any
657 JavaClassDescriptor desc = null;
658
659 Class<? extends JavaClassDescriptor> descriptorType
660 = context.getGraniteConfig().getJavaDescriptor(clazz.getName());
661 if (descriptorType != null) {
662 Class<?>[] argsDef = new Class[]{Class.class};
663 Object[] argsVal = new Object[]{clazz};
664 try {
665 desc = TypeUtil.newInstance(descriptorType, argsDef, argsVal);
666 }
667 catch (Exception e) {
668 throw new RuntimeException("Could not instantiate Java descriptor: " + descriptorType);
669 }
670 }
671
672 if (desc == null)
673 desc = new DefaultJavaClassDescriptor(clazz);
674
675 IndexedJavaClassDescriptor iDesc = new IndexedJavaClassDescriptor(storedClassDescriptors.size(), desc);
676
677 if (debug) log.debug("addToStoredClassDescriptors() - putting: name=%s, iDesc=%s", name, iDesc);
678
679 storedClassDescriptors.put(name, iDesc);
680
681 return iDesc;
682 }
683
684 protected IndexedJavaClassDescriptor getFromStoredClassDescriptors(Class<?> clazz) {
685 if (debug) log.debug("getFromStoredClassDescriptors(clazz=%s)", clazz);
686
687 String name = JavaClassDescriptor.getClassName(clazz);
688 IndexedJavaClassDescriptor iDesc = storedClassDescriptors.get(name);
689
690 if (debug) log.debug("getFromStoredClassDescriptors() -> %s", iDesc);
691
692 return iDesc;
693 }
694
695 ///////////////////////////////////////////////////////////////////////////
696 // Utilities.
697
698 protected Channel getChannel() {
699 if (channel == null) {
700 String channelId = context.getAMFContext().getChannelId();
701 if (channelId != null)
702 channel = context.getServicesConfig().findChannelById(channelId);
703 if (channel == null)
704 log.debug("Could not get channel for channel id: %s", channelId);
705 }
706 return channel;
707 }
708 }