root/pl/PLObjectInputReader.java

Revision 8 (checked in by rsz, 4 years ago)

Initial import

Line 
1 //
2 //      ===========================================================================
3 //
4 //      Title:          PLObjectInputReader.java
5 //      Description:    [Description]
6 //      Author:         Rapha‘l Szwarc http://alt.textdrive.com/pl/
7 //      Creation Date:  Thu Dec 09 2004
8 //      Legal:          Copyright (C) 2004 Rapha‘l Szwarc
9 //
10 //      This software is provided 'as-is', without any express or implied warranty.
11 //      In no event will the author be held liable for any damages arising from
12 //      the use of this software.
13 //
14 //      Permission is granted to anyone to use this software for any purpose,
15 //      including commercial applications, and to alter it and
16 //      redistribute it freely, subject to the following restrictions:
17 //
18 //      1. The origin of this software must not be misrepresented;
19 //      you must not claim that you wrote the original software.
20 //      If you use this software in a product, an acknowledgment
21 //      in the product documentation would be appreciated but is not required.
22 //
23 //      2. Altered source versions must be plainly marked as such,
24 //      and must not be misrepresented as being the original software.
25 //
26 //      3. This notice may not be removed or altered from any source distribution.
27 //
28 //      ---------------------------------------------------------------------------
29 //
30
31 package alt.dev.pl;
32
33 import java.io.Externalizable;
34 import java.io.Serializable;
35 import java.io.IOException;
36 import java.io.ByteArrayInputStream;
37 import java.io.ByteArrayOutputStream;
38 import java.io.DataOutputStream;
39 import java.io.ObjectStreamConstants;
40 import java.io.ObjectStreamClass;
41 import java.io.ObjectStreamField;
42 import java.io.ObjectInput;
43 import java.io.ObjectInputStream;
44
45 import java.lang.reflect.Array;
46 import java.lang.reflect.Constructor;
47 import java.lang.reflect.Field;
48 import java.lang.reflect.Method;
49 import java.lang.reflect.Modifier;
50 import java.lang.reflect.Proxy;
51 import java.lang.reflect.InvocationHandler;
52
53 import java.math.BigDecimal;
54 import java.math.BigInteger;
55
56 import java.net.InetAddress;
57 import java.net.URI;
58
59 import java.nio.charset.Charset;
60
61 import java.text.DateFormat;
62 import java.text.SimpleDateFormat;
63
64 import java.util.Arrays;
65 import java.util.Collections;
66 import java.util.Collection;
67 import java.util.List;
68 import java.util.ArrayList;
69 import java.util.Map;
70 import java.util.HashMap;
71 import java.util.LinkedHashMap;
72 import java.util.IdentityHashMap;
73 import java.util.Iterator;
74
75 import java.util.logging.Logger;
76 import java.util.logging.Level;
77
78 import java.util.Currency;
79 import java.util.Date;
80 import java.util.Locale;
81 import java.util.TimeZone;
82
83 public abstract class PLObjectInputReader extends Object
84 {
85
86 //      ===========================================================================
87 //      Constant(s)
88 //      ---------------------------------------------------------------------------
89
90         private static final Logger                     Log = Logger.getLogger( PLObjectInputReader.class.getName() );
91
92         private static final Class[]                    Classes =
93                                                         {
94                                                                 StringReader.class,
95                                                                 MapReader.class,
96                                                                 CollectionReader.class,
97                                                         };
98                                                        
99         private static final String                     CustomPrefix = "x-";
100
101 //      ===========================================================================
102 //      Class variable(s)
103 //      ---------------------------------------------------------------------------
104
105         private static final PLObjectInputReader[]      _readers = new PLObjectInputReader[ Classes.length ];
106         private static final Map                        _readersMap = new IdentityHashMap( Classes.length );
107
108 //      ===========================================================================
109 //      Instance variable(s)
110 //      ---------------------------------------------------------------------------
111
112 //      ===========================================================================
113 //      Constructor method(s)
114 //      ---------------------------------------------------------------------------
115
116         protected PLObjectInputReader()
117         {
118                 super();
119         }
120
121 //      ===========================================================================
122 //      Class method(s)
123 //      ---------------------------------------------------------------------------
124
125         static
126         {
127                 Class[] someClasses = PLObjectInputReader.Classes;
128                 int     count = someClasses.length;
129                
130                 for ( int index = 0; index < count; index++ )
131                 {
132                         Class   aClass = someClasses[ index ];
133                        
134                         try
135                         {
136                                 PLObjectInputReader     aReader = (PLObjectInputReader) aClass.newInstance();
137                                 Class                   aType = aReader.type();
138                                
139                                 if ( aType != null )
140                                 {
141                                         if ( _readersMap.containsKey( aType ) == false )
142                                         {
143                                                 _readers[ index ] = aReader;
144                                                 _readersMap.put( aType, aReader );
145                                         }
146                                         else
147                                         {
148                                                 throw new IllegalArgumentException( "PLObjectInputReader: duplicate type in " + aClass );
149                                         }
150                                 }
151                                 else
152                                 {
153                                         throw new IllegalArgumentException( "PLObjectInputReader: null type in " + aClass );
154                                 }
155                         }
156                         catch (IllegalArgumentException anException)
157                         {
158                                 throw anException;
159                         }
160                         catch (Throwable anException)
161                         {
162                                 throw new RuntimeException( anException.getMessage(), anException );
163                         }
164                 }
165         }
166                
167         public static void registerReader(final PLObjectInputReader aReader)
168         {
169                 if ( aReader != null )
170                 {
171                         if ( aReader.type() != null )
172                         {
173                                 if ( aReader.name() != null )
174                                 {
175                                         if ( aReader.name().startsWith( PLObjectInputReader.CustomPrefix ) == true )
176                                         {
177                                                 PLObjectInputReader.stringReader().registerCustomReader( aReader );
178                                                 PLObjectInputReader.mapReader().registerCustomReader( aReader );
179                                                
180                                                 return;
181                                         }
182
183                                         throw new IllegalArgumentException( "PLObjectInputReader.registerReader: missing custom prefix name in " + aReader );
184                                 }
185
186                                 throw new IllegalArgumentException( "PLObjectInputReader.registerReader: null name in " + aReader );
187                         }
188
189                         throw new IllegalArgumentException( "PLObjectInputReader.registerReader: null type in " + aReader );
190                 }
191                
192                 throw new IllegalArgumentException( "PLObjectInputReader.registerReader: null reader" );
193         }
194        
195         private static PLObjectInputReader[] readers()
196         {
197                 return _readers;
198         }
199        
200         private static Map readersMap()
201         {
202                 return _readersMap;
203         }
204        
205         private static StringReader stringReader()
206         {
207                 return (StringReader) PLObjectInputReader.readers()[ 0 ];
208         }
209        
210         private static MapReader mapReader()
211         {
212                 return (MapReader) PLObjectInputReader.readers()[ 1 ];
213         }
214        
215         public static PLObjectInputReader readerForObject(final Object anObject, final PLObjectInput anInput)
216         {
217                 if ( anObject != null )
218                 {
219                         Map                     aMap = PLObjectInputReader.readersMap();
220                         PLObjectInputReader     aReader = (PLObjectInputReader) aMap.get( anObject.getClass() );
221                        
222                         if ( aReader == null )
223                         {
224                                 PLObjectInputReader[]   someReaders = PLObjectInputReader.readers();
225                                 int                     count = someReaders.length;
226                                
227                                 for ( int index = 0; index < count; index++ )
228                                 {
229                                         PLObjectInputReader      anotherReader = someReaders[ index ];
230                                        
231                                         if ( anotherReader.canHandleObject( anObject ) == true )
232                                         {
233                                                 aReader = anotherReader;
234                                        
235                                                 break;
236                                         }
237                                 }
238                         }
239                        
240                         return aReader;
241                 }
242                
243                 return null;
244         }
245        
246         public static Object readObject(final Object anObject, final PLObjectInput anInput)
247         {
248                 PLObjectInputReader     aReader = PLObjectInputReader.readerForObject( anObject, anInput );
249                
250                 if ( aReader != null )
251                 {
252                         return aReader.read( anObject, anInput );
253                 }
254                
255                 return anObject;
256         }
257
258 //      ===========================================================================
259 //      Instance method(s)
260 //      ---------------------------------------------------------------------------
261
262         protected abstract Class type();
263        
264         protected abstract String name();
265
266         protected boolean canHandleObject(final Object anObject)
267         {
268                 if ( anObject != null )
269                 {
270                         Class   aType = this.type();
271                        
272                         if ( aType.isAssignableFrom( anObject.getClass() ) == true )
273                         {
274                                 return true;
275                         }
276                 }
277                
278                 return false;
279         }
280        
281         protected abstract Object read(final Object anObject, final PLObjectInput anInput);
282
283 //      ===========================================================================
284 //      StringReader method(s)
285 //      ---------------------------------------------------------------------------
286
287         private final static class StringReader extends PLObjectInputReader
288         {
289        
290                 private static final Class      Type = String.class;
291                
292                 private static final Class[]    Classes =
293                                                 {
294                                                         AliasReader.class,
295                                                         AliasPointerReader.class,
296
297                                                         BooleanReader.class,
298                                                         ClassReader.class,
299                                                         DoubleReader.class,
300                                                         FloatReader.class,
301                                                         IntegerReader.class,
302                                                         LongReader.class,
303                                                         ShortReader.class,
304                                                        
305                                                         BigDecimalReader.class,
306                                                         BigIntegerReader.class,
307                                                        
308                                                         InetAddressReader.class,
309                                                         URIReader.class,
310                                                        
311                                                         CharsetReader.class,
312                                                        
313                                                         CurrencyReader.class,
314                                                         DateReader.class,
315                                                         LocaleReader.class,
316                                                         TimeZoneReader.class,
317                                                 };
318                
319                 private final Map               _readers = new HashMap( StringReader.Classes.length );
320                 private final Map               _customReaders = new HashMap();
321
322                 protected StringReader()
323                 {
324                         super();
325                        
326                         this.init();
327                 }
328                
329                 private void init()
330                 {
331                         Class[] someClasses = StringReader.Classes;
332                         int     count = someClasses.length;
333                                
334                         for ( int index = 0; index < count; index++ )
335                         {
336                                 Class   aClass = someClasses[ index ];
337                                
338                                 try
339                                 {
340                                         PLObjectInputReader     aReader = (PLObjectInputReader) aClass.newInstance();
341                                         String                  aName = aReader.name();
342                                        
343                                         if ( aName != null )
344                                         {
345                                                 if ( _readers.containsKey( aName ) == false )
346                                                 {
347                                                         _readers.put( aName, aReader );
348                                                 }
349                                                 else
350                                                 {
351                                                         throw new IllegalArgumentException( "PLObjectInputReader.StringReader: duplicate name in " + aClass );
352                                                 }
353                                         }
354                                         else
355                                         {
356                                                 throw new IllegalArgumentException( "PLObjectInputReader.StringReader: null name in " + aClass );
357                                         }
358                                 }
359                                 catch (Exception anException)
360                                 {
361                                         throw new RuntimeException( anException.getMessage(), anException );
362                                 }
363                         }
364                 }
365        
366                 private Map customReaders()
367                 {
368                         return _customReaders;
369                 }
370                
371                 private void registerCustomReader(final PLObjectInputReader aReader)
372                 {
373                         if ( aReader != null )
374                         {
375                                 String  aName = aReader.name();
376                                
377                                 if ( aName != null )
378                                 {
379                                         Map     someReaders = this.customReaders();
380
381                                         if ( someReaders.containsKey( aName ) == false )
382                                         {
383                                                 someReaders.put( aName, aReader );
384                                         }
385                                         else
386                                         {
387                                                 throw new IllegalArgumentException( "PLObjectInputReader.StringReader.registerCustomReader: duplicate name in " + aReader );
388                                         }
389                                 }
390                                
391                                 return;
392                         }
393                        
394                         throw new IllegalArgumentException( "PLObjectInputReader.StringReader.registerCustomReader: null reader" );
395                 }
396                
397                 private Map readers()
398                 {
399                         return _readers;
400                 }
401                
402                 protected Class type()
403                 {
404                         return StringReader.Type;
405                 }
406                
407                 protected String name()
408                 {
409                         return null;
410                 }
411                
412                 private String nameWithValue(final String aValue)
413                 {
414                         if ( aValue.length() > 1 )
415                         {
416                                 int     anIndex = aValue.indexOf( ':' );
417                                
418                                 if ( anIndex > 0 )
419                                 {
420                                         return aValue.substring( 0, anIndex );
421                                 }
422                         }
423                        
424                         return null;
425                 }
426                
427                 protected Object read(final Object anObject, final PLObjectInput anInput)
428                 {
429                         String  aValue = (String) anObject;
430                        
431                         if ( aValue.length() > 0 )
432                         {
433                                 String  aName = this.nameWithValue( aValue );
434                                
435                                 if ( aName != null )
436                                 {
437                                         PLObjectInputReader     aReader = (PLObjectInputReader) this.customReaders().get( aName );
438                                        
439                                         if ( aReader == null )
440                                         {
441                                                  aReader = (PLObjectInputReader) this.readers().get( aName );
442                                         }
443                                        
444                                         if ( aReader != null )
445                                         {
446                                                 aValue = aValue.substring( aName.length() + 1, aValue.length() );
447                                        
448                                                 return aReader.read( aValue, anInput );
449                                         }
450                                 }
451                                
452                                 return aValue;
453                         }
454
455                         return null;
456                 }
457                
458         }
459
460 //      ===========================================================================
461 //      AliasReader method(s)
462 //      ---------------------------------------------------------------------------
463
464         private final static class AliasReader extends PLObjectInputReader
465         {
466        
467                 private static final String     Name = "&";
468                
469                 protected AliasReader()
470                 {
471                         super();
472                 }
473                
474                 protected Class type()
475                 {
476                         return null;
477                 }
478                
479                 protected String name()
480                 {
481                         return AliasReader.Name;
482                 }
483                
484                 protected Object read(final Object anObject, final PLObjectInput anInput)
485                 {
486                         return new Alias( anObject );
487                 }
488         }
489        
490 //      ===========================================================================
491 //      AliasPointerReader method(s)
492 //      ---------------------------------------------------------------------------
493
494         private final static class AliasPointerReader extends PLObjectInputReader
495         {
496        
497                 private static final String     Name = "*";
498                
499                 protected AliasPointerReader()
500                 {
501                         super();
502                 }
503                
504                 protected Class type()
505                 {
506                         return null;
507                 }
508                
509                 protected String name()
510                 {
511                         return AliasPointerReader.Name;
512                 }
513                
514                 protected Object read(final Object anObject, final PLObjectInput anInput)
515                 {
516                         if ( anInput.aliases().containsKey( anObject ) == true )
517                         {
518                                 return anInput.aliases().get( anObject );
519                         }
520                        
521                         Log.info( "Couldn't alias '" + anObject + "'." );
522
523                         return null;
524                 }
525         }
526        
527 //      ===========================================================================
528 //      BooleanReader method(s)
529 //      ---------------------------------------------------------------------------
530
531         private final static class BooleanReader extends PLObjectInputReader
532         {
533        
534                 private static final Class      Type = Boolean.class;
535                 private static final String     Name = Boolean.TYPE.getName();
536                
537                 protected BooleanReader()
538                 {
539                         super();
540                 }
541                
542                 protected Class type()
543                 {
544                         return BooleanReader.Type;
545                 }
546                
547                 protected String name()
548                 {
549                         return BooleanReader.Name;
550                 }
551                
552                 protected Object read(final Object anObject, final PLObjectInput anInput)
553                 {
554                         return Boolean.valueOf( (String) anObject );
555                 }
556                
557         }
558        
559 //      ===========================================================================
560 //      ClassReader method(s)
561 //      ---------------------------------------------------------------------------
562
563         private final static class ClassReader extends PLObjectInputReader
564         {
565        
566                 private static final Class      Type = Class.class;
567                 private static final String     Name = "x-class";
568                
569                 private static final Class[]    Types =
570                                                 {
571                                                         Byte.TYPE,
572                                                         Boolean.TYPE,
573                                                         Character.TYPE,
574                                                         Double.TYPE,
575                                                         Float.TYPE,
576                                                         Integer.TYPE,
577                                                         Long.TYPE,
578                                                         Short.TYPE,
579                                                         Void.TYPE
580                                                 };
581                                                
582                 private static final Map        TypesMap = new HashMap( Types.length );
583                 private static final Map        CodesMap = new HashMap( Types.length );
584
585                 protected ClassReader()
586                 {
587                         super();
588                 }
589                
590                 static
591                 {
592                         int     count = Types.length;
593                        
594                         for ( int index = 0; index < count; index++ )
595                         {
596                                 Class                   aType = Types[ index ];
597                                 ObjectStreamField       aField = new ObjectStreamField( aType.getName(), aType );
598                                 String                  aCode = new String( new char[] { aField.getTypeCode() } );
599                                
600                                 TypesMap.put( aType.getName(), aType );
601                                 CodesMap.put( aType, aCode );
602                         }
603                 }
604                
605                 protected Class type()
606                 {
607                         return ClassReader.Type;
608                 }
609                
610                 protected String name()
611                 {
612                         return ClassReader.Name;
613                 }
614                
615                 private Class classWithValue(final String aValue) throws Exception
616                 {
617                         String  aName = aValue;
618                         int     anIndex = aName.lastIndexOf( ']' );
619                         Class   aClass = null;
620                        
621                         if ( anIndex >= 0 )
622                         {
623                                 aName = aName.substring( anIndex + 1, aName.length() );
624                         }
625                        
626                         aClass = (Class) TypesMap.get( aName );
627                        
628                         if ( aClass == null )
629                         {
630                                 aClass = Class.forName( aName, true, Thread.currentThread().getContextClassLoader() );
631                         }
632                        
633                         return aClass;
634                 }
635                
636                 protected Object read(final Object anObject, final PLObjectInput anInput)
637                 {
638                         try
639                         {
640                                 String  aValue = (String) anObject;
641                                 Class   aClass = this.classWithValue( aValue );
642                                 int     anIndex = aValue.lastIndexOf( ']' );
643                                
644                                 if ( anIndex > 0 )
645                                 {
646                                         String  aCode = (String) CodesMap.get( aClass );
647                                        
648                                         if ( aCode == null )
649                                         {
650                                                 aCode = "L";
651                                         }
652                                        
653                                         aValue = aValue.replaceAll( "\\[\\]", "[" );
654                                         anIndex = aValue.lastIndexOf( '[' );
655                                         aValue = aValue.substring( 0, anIndex + 1 );
656                                         aValue = aValue + aCode;
657                                        
658                                         if ( aClass.isPrimitive() == false )
659                                         {
660                                                 aValue = aValue + aClass.getName() + ";";
661                                         }
662
663                                         aClass = Class.forName( aValue, true, Thread.currentThread().getContextClassLoader() );
664                                 }
665                                
666                                 return aClass;
667                         }
668                         catch (Throwable anException)
669                         {
670                                 Log.log( Level.FINER, anException.getMessage(), anException );
671                                 Log.info( "Couldn't convert '" + anObject + "'." );
672                         }
673                        
674                         return null;
675                 }
676                
677         }
678        
679 //      ===========================================================================
680 //      DoubleReader method(s)
681 //      ---------------------------------------------------------------------------
682
683         private final static class DoubleReader extends PLObjectInputReader
684         {
685        
686                 private static final Class      Type = Double.class;
687                 private static final String     Name = Double.TYPE.getName();
688                
689                 protected DoubleReader()
690                 {
691                         super();
692                 }
693                
694                 protected Class type()
695                 {
696                         return DoubleReader.Type;
697                 }
698                
699                 protected String name()
700                 {
701                         return DoubleReader.Name;
702                 }
703                
704                 protected Object read(final Object anObject, final PLObjectInput anInput)
705                 {
706                         try
707                         {
708                                 return Double.valueOf( (String) anObject );
709                         }
710                         catch (Exception anException)
711                         {
712                                 Log.log( Level.FINER, anException.getMessage(), anException );
713                                 Log.info( "Couldn't convert '" + anObject + "'." );
714                         }
715
716                         return null;
717                 }
718                
719         }
720        
721 //      ===========================================================================
722 //      FloatReader method(s)
723 //      ---------------------------------------------------------------------------
724
725         private final static class FloatReader extends PLObjectInputReader
726         {
727        
728                 private static final Class      Type = Float.class;
729                 private static final String     Name = Float.TYPE.getName();
730                
731                 protected FloatReader()
732                 {
733                         super();
734                 }
735                
736                 protected Class type()
737                 {
738                         return FloatReader.Type;
739                 }
740                
741                 protected String name()
742                 {
743                         return FloatReader.Name;
744                 }
745                
746                 protected Object read(final Object anObject, final PLObjectInput anInput)
747                 {
748                         try
749                         {
750                                 return Float.valueOf( (String) anObject );
751                         }
752                         catch (Exception anException)
753                         {
754                                 Log.log( Level.FINER, anException.getMessage(), anException );
755                                 Log.info( "Couldn't convert '" + anObject + "'." );
756                         }
757
758                         return null;
759                 }
760                
761         }
762        
763 //      ===========================================================================
764 //      IntegerReader method(s)
765 //      ---------------------------------------------------------------------------
766
767         private final static class IntegerReader extends PLObjectInputReader
768         {
769        
770                 private static final Class      Type = Integer.class;
771                 private static final String     Name = Integer.TYPE.getName();
772                
773                 protected IntegerReader()
774                 {
775                         super();
776                 }
777                
778                 protected Class type()
779                 {
780                         return IntegerReader.Type;
781                 }
782                
783                 protected String name()
784                 {
785                         return IntegerReader.Name;
786                 }
787                
788                 protected Object read(final Object anObject, final PLObjectInput anInput)
789                 {
790                         try
791                         {
792                                 return Integer.valueOf( (String) anObject );
793                         }
794                         catch (Exception anException)
795                         {
796                                 Log.log( Level.FINER, anException.getMessage(), anException );
797                                 Log.info( "Couldn't convert '" + anObject + "'." );
798                         }
799
800                         return null;
801                 }
802                
803         }
804        
805 //      ===========================================================================
806 //      LongReader method(s)
807 //      ---------------------------------------------------------------------------
808
809         private final static class LongReader extends PLObjectInputReader
810         {
811        
812                 private static final Class      Type = Long.class;
813                 private static final String     Name = Long.TYPE.getName();
814                
815                 protected LongReader()
816                 {
817                         super();
818                 }
819                
820                 protected Class type()
821                 {
822                         return LongReader.Type;
823                 }
824                
825                 protected String name()
826                 {
827                         return LongReader.Name;
828                 }