001 // SECTION-START[License Header]
002 // <editor-fold defaultstate="collapsed" desc=" Generated License ">
003 /*
004 * Copyright (c) 2009 The JOMC Project
005 * Copyright (c) 2005 Christian Schulte <cs@jomc.org>
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions
010 * are met:
011 *
012 * o Redistributions of source code must retain the above copyright
013 * notice, this list of conditions and the following disclaimer.
014 *
015 * o Redistributions in binary form must reproduce the above copyright
016 * notice, this list of conditions and the following disclaimer in
017 * the documentation and/or other materials provided with the
018 * distribution.
019 *
020 * THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
022 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
023 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
027 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
028 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
029 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
030 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 *
032 * $Id: DefaultObjectManager.java 968 2009-11-18 06:08:28Z schulte2005 $
033 *
034 */
035 // </editor-fold>
036 // SECTION-END
037 package org.jomc.ri;
038
039 import java.io.BufferedReader;
040 import java.io.File;
041 import java.io.FileInputStream;
042 import java.io.IOException;
043 import java.io.InputStream;
044 import java.io.InputStreamReader;
045 import java.lang.reflect.Array;
046 import java.lang.reflect.Method;
047 import java.lang.reflect.Proxy;
048 import java.net.URI;
049 import java.net.URL;
050 import java.text.MessageFormat;
051 import java.util.ArrayList;
052 import java.util.Comparator;
053 import java.util.Enumeration;
054 import java.util.HashMap;
055 import java.util.HashSet;
056 import java.util.LinkedList;
057 import java.util.List;
058 import java.util.Locale;
059 import java.util.Map;
060 import java.util.ResourceBundle;
061 import java.util.Set;
062 import java.util.TreeMap;
063 import java.util.logging.Level;
064 import java.util.logging.LogRecord;
065 import javax.xml.bind.JAXBContext;
066 import javax.xml.bind.JAXBElement;
067 import javax.xml.bind.JAXBException;
068 import javax.xml.bind.util.JAXBResult;
069 import javax.xml.bind.util.JAXBSource;
070 import javax.xml.transform.Transformer;
071 import javax.xml.transform.TransformerException;
072 import javax.xml.validation.Schema;
073 import org.jomc.ObjectManagementException;
074 import org.jomc.ObjectManager;
075 import org.jomc.ObjectManagerFactory;
076 import org.jomc.model.DefaultModelManager;
077 import org.jomc.model.DefaultModelObjectValidator;
078 import org.jomc.model.Dependency;
079 import org.jomc.model.Implementation;
080 import org.jomc.model.ImplementationReference;
081 import org.jomc.model.Implementations;
082 import org.jomc.model.Instance;
083 import org.jomc.model.Message;
084 import org.jomc.model.ModelObjectValidationReport;
085 import org.jomc.model.ModelObjectValidator;
086 import org.jomc.model.ModelProvider;
087 import org.jomc.model.Module;
088 import org.jomc.model.Modules;
089 import org.jomc.model.Multiplicity;
090 import org.jomc.model.ObjectFactory;
091 import org.jomc.model.Property;
092 import org.jomc.model.Specification;
093 import org.jomc.model.SpecificationReference;
094 import org.jomc.spi.Invocation;
095 import org.jomc.spi.Invoker;
096 import org.jomc.spi.Listener;
097 import org.jomc.spi.Locator;
098 import org.jomc.spi.Scope;
099 import org.jomc.util.WeakIdentityHashMap;
100 import org.xml.sax.SAXException;
101
102 // SECTION-START[Documentation]
103 // <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
104 /**
105 * Object management and configuration reference implementation.
106 * <p><b>Specifications</b><ul>
107 * <li>{@code org.jomc.ObjectManager} {@code 1.0} {@code Singleton}</li>
108 * </ul></p>
109 *
110 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a> 1.0
111 * @version $Id: DefaultObjectManager.java 968 2009-11-18 06:08:28Z schulte2005 $
112 */
113 // </editor-fold>
114 // SECTION-END
115 // SECTION-START[Annotations]
116 // <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
117 @javax.annotation.Generated( value = "org.jomc.tools.JavaSources",
118 comments = "See http://jomc.sourceforge.net/jomc/1.0-alpha-8/jomc-tools" )
119 // </editor-fold>
120 // SECTION-END
121 public class DefaultObjectManager implements ObjectManager
122 {
123 // SECTION-START[Constructors]
124 // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
125
126 /** Creates a new {@code DefaultObjectManager} instance. */
127 @javax.annotation.Generated( value = "org.jomc.tools.JavaSources",
128 comments = "See http://jomc.sourceforge.net/jomc/1.0-alpha-8/jomc-tools" )
129 public DefaultObjectManager()
130 {
131 // SECTION-START[Default Constructor]
132 super();
133 // SECTION-END
134 }
135 // </editor-fold>
136 // SECTION-END
137 // SECTION-START[ObjectManager]
138
139 public Object getObject( final Class specification )
140 {
141 if ( specification == null )
142 {
143 throw new NullPointerException( "specification" );
144 }
145
146 try
147 {
148 this.initialize();
149
150 final ClassLoader classLoader = getClassLoader( specification );
151 final Modules model = this.getModules( classLoader );
152 final Specification s = model.getSpecification( specification );
153
154 if ( s == null )
155 {
156 if ( this.isLoggable( Level.WARNING ) )
157 {
158 this.log( Level.WARNING, this.getMissingSpecificationMessage(
159 specification.getName() ), new Exception() );
160
161 }
162
163 return null;
164 }
165
166 Scope scope = null;
167 if ( s.getScope() != null )
168 {
169 scope = this.getScope( classLoader, s.getScope() );
170
171 if ( scope == null )
172 {
173 if ( this.isLoggable( Level.WARNING ) )
174 {
175 this.log( Level.WARNING, this.getMissingScopeMessage( s.getScope() ), null );
176 }
177
178 return null;
179 }
180 }
181
182 final Implementations available = model.getImplementations( s.getIdentifier() );
183 if ( available == null || available.getImplementation().isEmpty() )
184 {
185 if ( this.isLoggable( Level.WARNING ) )
186 {
187 this.log( Level.WARNING, this.getMissingImplementationsMessage(
188 specification.getName() ), new Exception() );
189
190 }
191
192 return null;
193 }
194
195 if ( s.getMultiplicity() == Multiplicity.ONE )
196 {
197 final Implementation i = available.getImplementation().get( 0 );
198
199 if ( i.getLocation() != null )
200 {
201 final Object object = this.getObject(
202 Class.forName( s.getClazz(), true, classLoader ), i.getLocationUri(), classLoader );
203
204 if ( object == null )
205 {
206 if ( this.isLoggable( Level.WARNING ) )
207 {
208 this.log( Level.WARNING, this.getMissingObjectMessage(
209 i.getIdentifier(), i.getName() ), new Exception() );
210
211 }
212
213 return null;
214 }
215
216 return object;
217 }
218 else if ( !i.isAbstract() )
219 {
220 final Instance instance = model.getInstance( i.getIdentifier() );
221 if ( instance == null )
222 {
223 if ( this.isLoggable( Level.WARNING ) )
224 {
225 this.log( Level.WARNING, this.getMissingInstanceMessage(
226 i.getIdentifier(), i.getName() ), new Exception() );
227
228 }
229
230 return null;
231 }
232
233 final Object object = this.getObject( scope, instance, classLoader );
234 if ( object == null )
235 {
236 if ( this.isLoggable( Level.WARNING ) )
237 {
238 this.log( Level.WARNING, this.getMissingObjectMessage(
239 i.getIdentifier(), i.getName() ), new Exception() );
240
241 }
242
243 return null;
244 }
245
246 return object;
247 }
248 }
249 else if ( s.getMultiplicity() == Multiplicity.MANY )
250 {
251 final List<Object> list = new ArrayList<Object>( available.getImplementation().size() );
252
253 for ( Implementation i : available.getImplementation() )
254 {
255 if ( i.getLocation() != null )
256 {
257 final Object o = this.getObject(
258 Class.forName( s.getClazz(), true, classLoader ), i.getLocationUri(), classLoader );
259
260 if ( o == null )
261 {
262 if ( this.isLoggable( Level.WARNING ) )
263 {
264 this.log( Level.WARNING, this.getMissingObjectMessage(
265 i.getIdentifier(), i.getName() ), new Exception() );
266
267 }
268 }
269 else
270 {
271 list.add( o );
272 }
273 }
274 else if ( !i.isAbstract() )
275 {
276 final Instance instance = model.getInstance( i.getIdentifier() );
277 if ( instance == null )
278 {
279 if ( this.isLoggable( Level.WARNING ) )
280 {
281 this.log( Level.WARNING, this.getMissingInstanceMessage(
282 i.getIdentifier(), i.getName() ), new Exception() );
283
284 }
285
286 return null;
287 }
288
289 final Object o = this.getObject( scope, instance, classLoader );
290 if ( o == null )
291 {
292 if ( this.isLoggable( Level.WARNING ) )
293 {
294 this.log( Level.WARNING, this.getMissingObjectMessage(
295 i.getIdentifier(), i.getName() ), new Exception() );
296
297 }
298 }
299 else
300 {
301 list.add( o );
302 }
303 }
304 }
305
306 return list.isEmpty()
307 ? null : list.toArray( (Object[]) Array.newInstance( specification, list.size() ) );
308
309 }
310 else if ( this.isLoggable( Level.WARNING ) )
311 {
312 this.log( Level.WARNING, this.getUnsupportedMultiplicityMessage(
313 s.getMultiplicity() ), new Exception() );
314
315 }
316
317 return null;
318 }
319 catch ( final Exception e )
320 {
321 throw new ObjectManagementException( e.getMessage(), e );
322 }
323 }
324
325 public Object getObject( final Class specification, final String implementationName )
326 {
327 if ( specification == null )
328 {
329 throw new NullPointerException( "specification" );
330 }
331 if ( implementationName == null )
332 {
333 throw new NullPointerException( "implementationName" );
334 }
335
336 try
337 {
338 this.initialize();
339
340 final ClassLoader classLoader = getClassLoader( specification );
341 final Modules model = this.getModules( classLoader );
342 final Specification s = model.getSpecification( specification );
343
344 if ( s == null )
345 {
346 if ( this.isLoggable( Level.WARNING ) )
347 {
348 this.log( Level.WARNING, this.getMissingSpecificationMessage(
349 specification.getName() ), new Exception() );
350
351 }
352
353 return null;
354 }
355
356 Scope scope = null;
357 if ( s.getScope() != null )
358 {
359 scope = this.getScope( classLoader, s.getScope() );
360
361 if ( scope == null )
362 {
363 if ( this.isLoggable( Level.WARNING ) )
364 {
365 this.log( Level.WARNING, this.getMissingScopeMessage( s.getScope() ), null );
366 }
367
368 return null;
369 }
370 }
371
372 final Implementations available = model.getImplementations( s.getIdentifier() );
373 if ( available == null || available.getImplementation().isEmpty() )
374 {
375 if ( this.isLoggable( Level.WARNING ) )
376 {
377 this.log( Level.WARNING, this.getMissingImplementationsMessage(
378 specification.getName() ), new Exception() );
379
380 }
381
382 return null;
383 }
384
385 final Implementation i = available.getImplementationByName( implementationName );
386 if ( i == null )
387 {
388 if ( this.isLoggable( Level.WARNING ) )
389 {
390 this.log( Level.WARNING, this.getMissingImplementationMessage(
391 implementationName, s.getIdentifier() ), new Exception() );
392
393 }
394
395 return null;
396 }
397
398 if ( i.getLocation() != null )
399 {
400 final Object object = this.getObject(
401 Class.forName( s.getClazz(), true, classLoader ), i.getLocationUri(), classLoader );
402
403 if ( object == null )
404 {
405 if ( this.isLoggable( Level.WARNING ) )
406 {
407 this.log( Level.WARNING, this.getMissingObjectMessage(
408 i.getIdentifier(), i.getName() ), new Exception() );
409
410 }
411
412 return null;
413 }
414
415 return object;
416 }
417 else if ( !i.isAbstract() )
418 {
419 final Instance instance = model.getInstance( i.getIdentifier() );
420 if ( instance == null )
421 {
422 if ( this.isLoggable( Level.WARNING ) )
423 {
424 this.log( Level.WARNING, this.getMissingInstanceMessage(
425 i.getIdentifier(), i.getName() ), new Exception() );
426
427 }
428
429 return null;
430 }
431
432 final Object object = this.getObject( scope, instance, classLoader );
433 if ( object == null )
434 {
435 if ( this.isLoggable( Level.WARNING ) )
436 {
437 this.log( Level.WARNING, this.getMissingObjectMessage(
438 i.getIdentifier(), i.getName() ), new Exception() );
439
440 }
441
442 return null;
443 }
444
445 return object;
446 }
447
448 return null;
449 }
450 catch ( final Exception e )
451 {
452 throw new ObjectManagementException( e.getMessage(), e );
453 }
454 }
455
456 public Object getDependency( final Object object, final String dependencyName )
457 {
458 if ( object == null )
459 {
460 throw new NullPointerException( "object" );
461 }
462 if ( dependencyName == null )
463 {
464 throw new NullPointerException( "dependencyName" );
465 }
466
467 try
468 {
469 this.initialize();
470
471 final ClassLoader classLoader = getClassLoader( object.getClass() );
472 final Modules model = this.getModules( classLoader );
473 final Instance instance = model.getInstance( object );
474
475 if ( instance == null )
476 {
477 if ( this.isLoggable( Level.WARNING ) )
478 {
479 this.log( Level.WARNING, this.getMissingObjectInstanceMessage( object ), new Exception() );
480 }
481
482 return null;
483 }
484
485 synchronized ( instance )
486 {
487 final Dependency dependency = instance.getDependencies() != null
488 ? instance.getDependencies().getDependency( dependencyName ) : null;
489
490 if ( dependency == null )
491 {
492 if ( this.isLoggable( Level.WARNING ) )
493 {
494 this.log( Level.WARNING, this.getMissingDependencyMessage(
495 dependencyName, instance.getIdentifier() ), new Exception() );
496
497 }
498
499 return null;
500 }
501
502 Object o = instance.getDependencyObjects().get( dependencyName );
503 if ( o == null )
504 {
505 final Specification ds = model.getSpecification( dependency.getIdentifier() );
506 if ( ds == null )
507 {
508 if ( this.isLoggable( Level.WARNING ) )
509 {
510 this.log( Level.WARNING, this.getMissingSpecificationMessage(
511 dependency.getIdentifier() ), new Exception() );
512
513 }
514
515 return null;
516 }
517
518 Scope scope = null;
519 if ( ds.getScope() != null )
520 {
521 scope = this.getScope( classLoader, ds.getScope() );
522
523 if ( scope == null )
524 {
525 if ( this.isLoggable( Level.WARNING ) )
526 {
527 this.log( Level.WARNING, this.getMissingScopeMessage( ds.getScope() ), null );
528 }
529
530 return null;
531 }
532 }
533
534 final Implementations available = model.getImplementations( ds.getIdentifier() );
535 if ( available == null || available.getImplementation().isEmpty() )
536 {
537 if ( !dependency.isOptional() && this.isLoggable( Level.WARNING ) )
538 {
539 this.log( Level.WARNING, this.getMissingImplementationsMessage(
540 dependency.getIdentifier() ), new Exception() );
541
542 }
543
544 return null;
545 }
546
547 if ( dependency.getImplementationName() != null )
548 {
549 final Implementation i =
550 available.getImplementationByName( dependency.getImplementationName() );
551
552 if ( i == null )
553 {
554 if ( !dependency.isOptional() && this.isLoggable( Level.WARNING ) )
555 {
556 this.log( Level.WARNING, this.getMissingImplementationMessage(
557 dependency.getImplementationName(), dependency.getIdentifier() ), new Exception() );
558
559 }
560
561 return null;
562 }
563
564 if ( i.getLocation() != null )
565 {
566 o = this.getObject(
567 Class.forName( ds.getClazz(), true, classLoader ), i.getLocationUri(), classLoader );
568
569 if ( o == null )
570 {
571 if ( this.isLoggable( Level.WARNING ) )
572 {
573 this.log( Level.WARNING, this.getMissingObjectMessage(
574 i.getIdentifier(), i.getName() ), new Exception() );
575
576 }
577
578 return null;
579 }
580 }
581 else if ( !i.isAbstract() )
582 {
583 final Instance di = model.getInstance( i.getIdentifier(), dependency );
584 if ( di == null )
585 {
586 if ( this.isLoggable( Level.WARNING ) )
587 {
588 this.log( Level.WARNING, this.getMissingInstanceMessage(
589 i.getIdentifier(), i.getName() ), new Exception() );
590
591 }
592
593 return null;
594 }
595
596 o = this.getObject( scope, di, classLoader );
597 if ( o == null )
598 {
599 if ( this.isLoggable( Level.WARNING ) )
600 {
601 this.log( Level.WARNING, this.getMissingObjectMessage(
602 i.getIdentifier(), i.getName() ), new Exception() );
603
604 }
605
606 return null;
607 }
608 }
609 }
610 else if ( ds.getMultiplicity() == Multiplicity.ONE )
611 {
612 final Implementation ref = available.getImplementation().get( 0 );
613 if ( ref.getLocation() != null )
614 {
615 o = this.getObject(
616 Class.forName( ds.getClazz(), true, classLoader ), ref.getLocationUri(), classLoader );
617
618 if ( o == null )
619 {
620 if ( this.isLoggable( Level.WARNING ) )
621 {
622 this.log( Level.WARNING, this.getMissingObjectMessage(
623 ref.getIdentifier(), ref.getName() ), new Exception() );
624
625 }
626
627 return null;
628 }
629 }
630 else if ( !ref.isAbstract() )
631 {
632 final Instance di = model.getInstance( ref.getIdentifier(), dependency );
633 if ( di == null )
634 {
635 if ( this.isLoggable( Level.WARNING ) )
636 {
637 this.log( Level.WARNING, this.getMissingInstanceMessage(
638 ref.getIdentifier(), ref.getName() ), new Exception() );
639
640 }
641
642 return null;
643 }
644
645 o = this.getObject( scope, di, classLoader );
646 if ( o == null )
647 {
648 if ( this.isLoggable( Level.WARNING ) )
649 {
650 this.log( Level.WARNING, this.getMissingObjectMessage(
651 ref.getIdentifier(), ref.getName() ), new Exception() );
652
653 }
654
655 return null;
656 }
657 }
658 }
659 else
660 {
661 final List<Object> list = new ArrayList<Object>( available.getImplementation().size() );
662
663 for ( Implementation a : available.getImplementation() )
664 {
665 if ( a.getLocation() != null )
666 {
667 final Object o2 = this.getObject( Class.forName( ds.getClazz(), true, classLoader ),
668 a.getLocationUri(), classLoader );
669
670 if ( o2 == null )
671 {
672 if ( this.isLoggable( Level.WARNING ) )
673 {
674 this.log( Level.WARNING, this.getMissingObjectMessage(
675 a.getIdentifier(), a.getName() ), new Exception() );
676
677 }
678 }
679 else
680 {
681 list.add( o2 );
682 }
683 }
684 else if ( !a.isAbstract() )
685 {
686 final Instance di = model.getInstance( a.getIdentifier(), dependency );
687 if ( di == null )
688 {
689 if ( this.isLoggable( Level.WARNING ) )
690 {
691 this.log( Level.WARNING, this.getMissingInstanceMessage(
692 a.getIdentifier(), a.getName() ), new Exception() );
693
694 }
695
696 return null;
697 }
698
699 final Object o2 = this.getObject( scope, di, classLoader );
700 if ( o2 == null )
701 {
702 if ( this.isLoggable( Level.WARNING ) )
703 {
704 this.log( Level.WARNING, this.getMissingObjectMessage(
705 a.getIdentifier(), a.getName() ), new Exception() );
706
707 }
708 }
709 else
710 {
711 list.add( o2 );
712 }
713 }
714 }
715
716 final Class specClass = Class.forName( ds.getClazz(), true, classLoader );
717 o = list.isEmpty()
718 ? null : list.toArray( (Object[]) Array.newInstance( specClass, list.size() ) );
719
720 }
721 }
722
723 if ( o != null && dependency.isBound() )
724 {
725 instance.getDependencyObjects().put( dependencyName, o );
726 }
727
728 return o;
729 }
730 }
731 catch ( final Exception e )
732 {
733 throw new ObjectManagementException( e.getMessage(), e );
734 }
735 }
736
737 public Object getProperty( final Object object, final String propertyName )
738 {
739 if ( object == null )
740 {
741 throw new NullPointerException( "object" );
742 }
743 if ( propertyName == null )
744 {
745 throw new NullPointerException( "propertyName" );
746 }
747
748 try
749 {
750 this.initialize();
751
752 final ClassLoader classLoader = getClassLoader( object.getClass() );
753 final Modules model = this.getModules( classLoader );
754 final Instance instance = model.getInstance( object );
755
756 if ( instance == null )
757 {
758 if ( this.isLoggable( Level.WARNING ) )
759 {
760 this.log( Level.WARNING, this.getMissingObjectInstanceMessage( object ), new Exception() );
761 }
762
763 return null;
764 }
765
766 synchronized ( instance )
767 {
768 Object value = instance.getPropertyObjects().get( propertyName );
769 if ( value == null )
770 {
771 final Property property =
772 instance.getProperties() != null ? instance.getProperties().getProperty( propertyName ) : null;
773
774 if ( property == null )
775 {
776 if ( this.isLoggable( Level.WARNING ) )
777 {
778 this.log( Level.WARNING, this.getMissingPropertyMessage(
779 propertyName, object.getClass().getName() ), new Exception() );
780
781 }
782
783 return null;
784 }
785
786 value = property.getJavaValue( classLoader );
787 if ( value != null )
788 {
789 instance.getPropertyObjects().put( propertyName, value );
790 }
791 }
792
793 return value;
794 }
795 }
796 catch ( final Exception e )
797 {
798 throw new ObjectManagementException( e.getMessage(), e );
799 }
800 }
801
802 public String getMessage( final Object object, final String messageName, final Locale locale,
803 final Object arguments )
804 {
805 if ( object == null )
806 {
807 throw new NullPointerException( "object" );
808 }
809 if ( messageName == null )
810 {
811 throw new NullPointerException( "messageName" );
812 }
813 if ( locale == null )
814 {
815 throw new NullPointerException( "locale" );
816 }
817
818 try
819 {
820 this.initialize();
821
822 final ClassLoader classLoader = getClassLoader( object.getClass() );
823 final Modules model = this.getModules( classLoader );
824 final Instance instance = model.getInstance( object );
825
826 if ( instance == null )
827 {
828 if ( this.isLoggable( Level.WARNING ) )
829 {
830 this.log( Level.WARNING, this.getMissingObjectInstanceMessage( object ), new Exception() );
831 }
832
833 return null;
834 }
835
836 synchronized ( instance )
837 {
838 final Message message =
839 instance.getMessages() != null ? instance.getMessages().getMessage( messageName ) : null;
840
841 if ( message == null || message.getTemplate() == null )
842 {
843 if ( this.isLoggable( Level.WARNING ) )
844 {
845 this.log( Level.WARNING, this.getMissingMessageMessage(
846 messageName, object.getClass().getName() ), new Exception() );
847
848 }
849
850 return null;
851 }
852
853 final MessageFormat fmt = new MessageFormat( message.getTemplate().getText(
854 locale.getLanguage().toLowerCase( Locale.ENGLISH ) ).getValue(), locale );
855
856 return fmt.format( arguments );
857 }
858 }
859 catch ( final Exception e )
860 {
861 throw new ObjectManagementException( e.getMessage(), e );
862 }
863 }
864
865 // SECTION-END
866 // SECTION-START[DefaultObjectManager]
867 /** Constant for the {@code Singleton} scope identifier. */
868 protected static final String SINGLETON_SCOPE_IDENTIFIER = "Singleton";
869
870 /** Empty {@code URL} array. */
871 private static final URL[] NO_URLS =
872 {
873 };
874
875 /**
876 * Log level events are logged at by default.
877 * @see #getDefaultLogLevel()
878 */
879 private static final Level DEFAULT_LOG_LEVEL = Level.WARNING;
880
881 /** Default log level. */
882 private static volatile Level defaultLogLevel;
883
884 /** Name of the platform's bootstrap class loader class. */
885 private static volatile String bootstrapClassLoaderClassName;
886
887 private static volatile boolean bootstrapClassLoaderClassNameInitialized;
888
889 /** {@code ClassLoader} instance representing the bootstrap class loader. */
890 private static final ClassLoader BOOTSTRAP_CLASSLOADER = new ClassLoader( null )
891 {
892 };
893
894 /** Listeners of the instance. */
895 private List<Listener> listeners;
896
897 /** Flag indicating that initialization has been performed. */
898 private boolean initialized;
899
900 /** Log level of the instance. */
901 private Level logLevel;
902
903 /** Modules of the instance. */
904 private final Map<ClassLoader, Modules> modules = new WeakIdentityHashMap();
905
906 /** Invokers of the instance. */
907 private final Map<ClassLoader, Invoker> invokers = new WeakIdentityHashMap();
908
909 /** Scopes of the instance. */
910 private final Map<ClassLoader, Map<String, Scope>> scopes = new WeakIdentityHashMap();
911
912 /** Locators of the instance. */
913 private final Map<ClassLoader, Map<String, Locator>> locators = new WeakIdentityHashMap();
914
915 /** Objects of the instance. */
916 private final Map<ClassLoader, Map<Object, Instance>> objects = new WeakIdentityHashMap();
917
918 /** {@code ObjectManager} singletons. */
919 private static final Map<ClassLoader, ObjectManager> singletons = new WeakIdentityHashMap();
920
921 /**
922 * Default {@link ObjectManagerFactory#getObjectManager(ClassLoader)} implementation.
923 *
924 * @return The default {@code ObjectManager} singleton instance.
925 *
926 * @see ObjectManagerFactory#getObjectManager(ClassLoader)
927 */
928 public static ObjectManager getObjectManager( final ClassLoader classLoader )
929 {
930 synchronized ( singletons )
931 {
932 final ClassLoader singletonsLoader = getClassLoader( classLoader );
933 ObjectManager manager = singletons.get( singletonsLoader );
934 if ( manager == null )
935 {
936 manager = ObjectManagerFactory.newObjectManager( classLoader );
937 singletons.put( singletonsLoader, manager );
938 }
939
940 return (ObjectManager) manager.getObject( ObjectManager.class );
941 }
942 }
943
944 /**
945 * Gets the list of registered listeners.
946 * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
947 * to the returned list will be present inside the object. This is why there is no {@code set} method for the
948 * listeners property.</p>
949 *
950 * @return The list of registered listeners.
951 */
952 public List<Listener> getListeners()
953 {
954 if ( this.listeners == null )
955 {
956 this.listeners = new LinkedList<Listener>();
957 }
958
959 return this.listeners;
960 }
961
962 /**
963 * Gets the default log level events are logged at.
964 * <p>The default log level is controlled by system property
965 * {@code org.jomc.ri.DefaultObjectManager.defaultLogLevel} holding the log level to log events at by default.
966 * If that property is not set, the {@code WARNING} default is returned.</p>
967 *
968 * @return The log level events are logged at by default.
969 *
970 * @see #getLogLevel()
971 * @see Level#parse(java.lang.String)
972 */
973 public static Level getDefaultLogLevel()
974 {
975 if ( defaultLogLevel == null )
976 {
977 defaultLogLevel = Level.parse( System.getProperty( "org.jomc.ri.DefaultObjectManager.defaultLogLevel",
978 DEFAULT_LOG_LEVEL.getName() ) );
979
980 }
981
982 return defaultLogLevel;
983 }
984
985 /**
986 * Sets the default log level events are logged at.
987 *
988 * @param value The new default level events are logged at or {@code null}.
989 *
990 * @see #getDefaultLogLevel()
991 */
992 public static void setDefaultLogLevel( final Level value )
993 {
994 defaultLogLevel = value;
995 }
996
997 /**
998 * Gets the log level of the instance.
999 *
1000 * @return The log level of the instance.
1001 *
1002 * @see #getDefaultLogLevel()
1003 * @see #setLogLevel(java.util.logging.Level)
1004 * @see #isLoggable(java.util.logging.Level)
1005 */
1006 public Level getLogLevel()
1007 {
1008 if ( this.logLevel == null )
1009 {
1010 this.logLevel = getDefaultLogLevel();
1011 this.log( Level.CONFIG, this.getMessage( "defaultLogLevelInfo", new Object[]
1012 {
1013 this.getClass().getCanonicalName(), this.logLevel.getLocalizedName()
1014 } ), null );
1015
1016 }
1017
1018 return this.logLevel;
1019 }
1020
1021 /**
1022 * Sets the log level of the instance.
1023 *
1024 * @param value The new log level of the instance or {@code null}.
1025 *
1026 * @see #getLogLevel()
1027 * @see #isLoggable(java.util.logging.Level)
1028 */
1029 public void setLogLevel( final Level value )
1030 {
1031 this.logLevel = value;
1032 }
1033
1034 /**
1035 * Checks if a message at a given level is provided to the listeners of the instance.
1036 *
1037 * @param level The level to test.
1038 *
1039 * @return {@code true} if messages at {@code level} are provided to the listeners of the instance;
1040 * {@code false} if messages at {@code level} are not provided to the listeners of the instance.
1041 *
1042 * @throws NullPointerException if {@code level} is {@code null}.
1043 *
1044 * @see #getLogLevel()
1045 * @see #setLogLevel(java.util.logging.Level)
1046 * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
1047 */
1048 public boolean isLoggable( final Level level )
1049 {
1050 if ( level == null )
1051 {
1052 throw new NullPointerException( "level" );
1053 }
1054
1055 return level.intValue() >= this.getLogLevel().intValue();
1056 }
1057
1058 /**
1059 * Gets the name of the platform's bootstrap class loader class.
1060 * <p>The name of the platform's bootstrap class loader class is controlled by system property
1061 * {@code org.jomc.ri.DefaultObjectManager.bootstrapClassLoaderClassName} holding the name of the platform's
1062 * bootstrap class loader class. If that property is not set, the bootstrap class loader is assumed to be
1063 * represented by a {@code null} parent class loader.</p>
1064 *
1065 * @return The name of the platform's bootstrap class loader class or {@code null}.
1066 *
1067 * @see #getClassLoader(java.lang.ClassLoader)
1068 */
1069 public static String getBootstrapClassLoaderClassName()
1070 {
1071 if ( bootstrapClassLoaderClassName == null && !bootstrapClassLoaderClassNameInitialized )
1072 {
1073 bootstrapClassLoaderClassName =
1074 System.getProperty( "org.jomc.ri.DefaultObjectManager.bootstrapClassLoaderClassName" );
1075
1076 bootstrapClassLoaderClassNameInitialized = true;
1077 }
1078
1079 return bootstrapClassLoaderClassName;
1080 }
1081
1082 /**
1083 * Sets the name of the platform's bootstrap class loader class.
1084 *
1085 * @param value The new name of the platform's bootstrap class loader class or {@code null}.
1086 *
1087 * @see #getBootstrapClassLoaderClassName()
1088 */
1089 public static void setBootstrapClassLoaderClassName( final String value )
1090 {
1091 bootstrapClassLoaderClassName = value;
1092 bootstrapClassLoaderClassNameInitialized = false;
1093 }
1094
1095 /**
1096 * Gets the modules of a given class loader.
1097 *
1098 * @param classLoader The class loader to get the modules of.
1099 *
1100 * @return The modules of the given class loader.
1101 *
1102 * @throws NullPointerException if {@code classLoader} is {@code null},
1103 */
1104 public Modules getModules( final ClassLoader classLoader )
1105 {
1106 if ( classLoader == null )
1107 {
1108 throw new NullPointerException( "classLoader" );
1109 }
1110
1111 synchronized ( this.modules )
1112 {
1113 Modules cachedModules = this.modules.get( classLoader );
1114
1115 if ( cachedModules == null )
1116 {
1117 try
1118 {
1119 final DefaultModelManager defaultModelManager = new DefaultModelManager();
1120 defaultModelManager.setLogLevel( this.getLogLevel() );
1121 defaultModelManager.getListeners().add( new DefaultModelManager.Listener()
1122 {
1123
1124 public void onLog( final Level level, final String message, final Throwable t )
1125 {
1126 log( level, message, t );
1127 }
1128
1129 } );
1130
1131 final ObjectFactory objectFactory = new ObjectFactory();
1132 final JAXBContext context = defaultModelManager.getContext( classLoader );
1133 final Schema schema = defaultModelManager.getSchema( classLoader );
1134
1135 cachedModules = defaultModelManager.getClasspathModules(
1136 classLoader, DefaultModelManager.getDefaultModuleLocation() );
1137
1138 final Map<String, Class<ModelProvider>> providers =
1139 new TreeMap<String, Class<ModelProvider>>( new Comparator<String>()
1140 {
1141
1142 public int compare( final String key1, final String key2 )
1143 {
1144 return key1.compareTo( key2 );
1145 }
1146
1147 } );
1148
1149 final File platformProviders = new File( new StringBuilder().append(
1150 System.getProperty( "java.home" ) ).append( File.separator ).append( "jre" ).
1151 append( File.separator ).append( "lib" ).append( File.separator ).append( "jomc.properties" ).
1152 toString() );
1153
1154 if ( platformProviders.exists() )
1155 {
1156 if ( this.isLoggable( Level.CONFIG ) )
1157 {
1158 this.log( Level.CONFIG, this.getMessage( "processing", new Object[]
1159 {
1160 platformProviders.getAbsolutePath()
1161 } ), null );
1162
1163 }
1164
1165 final java.util.Properties p = new java.util.Properties();
1166 final InputStream in = new FileInputStream( platformProviders );
1167 p.load( in );
1168 in.close();
1169
1170 for ( Map.Entry e : p.entrySet() )
1171 {
1172 if ( e.getKey().toString().startsWith( "org.jomc.model.ModelProvider." ) )
1173 {
1174 providers.put( e.getKey().toString(), (Class<ModelProvider>) Class.forName(
1175 e.getValue().toString(), true, classLoader ) );
1176
1177 }
1178 }
1179 }
1180
1181 final Enumeration<URL> serviceProviders =
1182 classLoader.getResources( "META-INF/services/org.jomc.model.ModelProvider" );
1183
1184 if ( serviceProviders != null )
1185 {
1186 for ( ; serviceProviders.hasMoreElements(); )
1187 {
1188 String line;
1189 final URL serviceProvider = serviceProviders.nextElement();
1190
1191 if ( this.isLoggable( Level.CONFIG ) )
1192 {
1193 this.log( Level.CONFIG, this.getMessage( "processing", new Object[]
1194 {
1195 serviceProvider.toExternalForm()
1196 } ), null );
1197
1198 }
1199
1200 final BufferedReader reader =
1201 new BufferedReader( new InputStreamReader( serviceProvider.openStream(), "UTF-8" ) );
1202
1203 while ( ( line = reader.readLine() ) != null )
1204 {
1205 if ( line.contains( "#" ) )
1206 {
1207 continue;
1208 }
1209
1210 providers.put( "org.jomc.model.ModelProvider." + providers.size(),
1211 (Class<ModelProvider>) Class.forName( line, true, classLoader ) );
1212
1213 }
1214
1215 reader.close();
1216 }
1217 }
1218
1219 for ( Class<ModelProvider> provider : providers.values() )
1220 {
1221 if ( this.isLoggable( Level.CONFIG ) )
1222 {
1223 this.log( Level.CONFIG, this.getMessage( "modelProviderInfo", new Object[]
1224 {
1225 provider.getName()
1226 } ), null );
1227
1228 }
1229
1230 final ModelProvider modelProvider = provider.newInstance();
1231 final Modules providerModules = modelProvider.getModules( classLoader, cachedModules );
1232 if ( providerModules != null )
1233 {
1234 cachedModules.getModule().addAll( providerModules.getModule() );
1235 }
1236 }
1237
1238 final Module classpathModule =
1239 cachedModules.getClasspathModule( Modules.getDefaultClasspathModuleName(), classLoader );
1240
1241 if ( classpathModule != null )
1242 {
1243 cachedModules.getModule().add( classpathModule );
1244 }
1245
1246 final List<Transformer> defaultTransformers = defaultModelManager.getClasspathTransformers(
1247 classLoader, DefaultModelManager.getDefaultTransformerLocation() );
1248
1249 for ( Transformer t : defaultTransformers )
1250 {
1251 final JAXBElement<Modules> e = objectFactory.createModules( cachedModules );
1252 final JAXBSource source = new JAXBSource( context, e );
1253 final JAXBResult result = new JAXBResult( context );
1254 t.transform( source, result );
1255 cachedModules = ( (JAXBElement<Modules>) result.getResult() ).getValue();
1256 }
1257
1258 final ModelObjectValidator modelObjectValidator = new DefaultModelObjectValidator();
1259 final ModelObjectValidationReport validationReport = modelObjectValidator.validateModules(
1260 objectFactory.createModules( cachedModules ), context, schema );
1261
1262 for ( ModelObjectValidationReport.Detail d : validationReport.getDetails() )
1263 {
1264 if ( this.isLoggable( d.getLevel() ) )
1265 {
1266 this.log( d.getLevel(), d.getMessage(), null );
1267 }
1268 }
1269
1270 if ( validationReport.isModelObjectValid() )
1271 {
1272 final ClassLoader objectsLoader = getClassLoader( classLoader );
1273 Map<Object, Instance> objectMap = this.objects.get( objectsLoader );
1274 if ( objectMap == null )
1275 {
1276 objectMap = new WeakIdentityHashMap();
1277 this.objects.put( objectsLoader, objectMap );
1278 }
1279
1280 this.modules.put( classLoader, new Modules( cachedModules, objectMap ) );
1281
1282 if ( this.isLoggable( Level.FINE ) )
1283 {
1284 this.log( Level.FINE, this.getModulesReport( cachedModules, classLoader ), null );
1285 }
1286 }
1287 else
1288 {
1289 cachedModules = null;
1290 }
1291 }
1292 catch ( final ClassNotFoundException e )
1293 {
1294 if ( this.isLoggable( Level.SEVERE ) )
1295 {
1296 this.log( Level.SEVERE, e.getMessage(), e );
1297 }
1298
1299 cachedModules = null;
1300 }
1301 catch ( final InstantiationException e )
1302 {
1303 if ( this.isLoggable( Level.SEVERE ) )
1304 {
1305 this.log( Level.SEVERE, e.getMessage(), e );
1306 }
1307
1308 cachedModules = null;
1309 }
1310 catch ( final IllegalAccessException e )
1311 {
1312 if ( this.isLoggable( Level.SEVERE ) )
1313 {
1314 this.log( Level.SEVERE, e.getMessage(), e );
1315 }
1316
1317 cachedModules = null;
1318 }
1319 catch ( final TransformerException e )
1320 {
1321 if ( this.isLoggable( Level.SEVERE ) )
1322 {
1323 this.log( Level.SEVERE, e.getMessage(), e );
1324 }
1325
1326 cachedModules = null;
1327 }
1328 catch ( final IOException e )
1329 {
1330 if ( this.isLoggable( Level.SEVERE ) )
1331 {
1332 this.log( Level.SEVERE, e.getMessage(), e );
1333 }
1334
1335 cachedModules = null;
1336 }
1337 catch ( final SAXException e )
1338 {
1339 if ( this.isLoggable( Level.SEVERE ) )
1340 {
1341 this.log( Level.SEVERE, e.getMessage(), e );
1342 }
1343
1344 cachedModules = null;
1345 }
1346 catch ( final JAXBException e )
1347 {
1348 if ( this.isLoggable( Level.SEVERE ) )
1349 {
1350 this.log( Level.SEVERE, e.getMessage(), e );
1351 }
1352
1353 cachedModules = null;
1354 }
1355 finally
1356 {
1357 if ( cachedModules == null )
1358 {
1359 cachedModules = new Modules();
1360 }
1361 }
1362 }
1363
1364 return cachedModules;
1365 }
1366 }
1367
1368 /**
1369 * Gets the class loader of a given class.
1370 *
1371 * @param clazz The class whose class loader to return.
1372 *
1373 * @return The class loader of {@code clazz}.
1374 *
1375 * @throws NullPointerException if {@code clazz} is {@code null}.
1376 */
1377 public static ClassLoader getClassLoader( final Class clazz )
1378 {
1379 if ( clazz == null )
1380 {
1381 throw new NullPointerException( "clazz" );
1382 }
1383
1384 ClassLoader cl = clazz.getClassLoader();
1385 if ( cl == null )
1386 {
1387 cl = BOOTSTRAP_CLASSLOADER;
1388 }
1389
1390 return cl;
1391 }
1392
1393 /**
1394 * Gets the parent class loader of a given class loader recursively.
1395 * <p>This method recursively finds the parent class loader of the given class loader. Recursion stops at the
1396 * platform's bootstrap class loader. That class loader is detected when either the current class loader has no
1397 * parent (a call to the {@code getParent()} method returns {@code null}) or when the class name of the
1398 * current class loader's parent class loader is equal to the name returned by method
1399 * {@code getBootstrapClassLoaderClassName()}. Configuration of the name of the platform's bootstrap class loader
1400 * class is needed when the platform's {@code getParent()} method of the {@code ClassLoader} class does not return
1401 * {@code null} to indicate the bootstrap class loader but instead returns an instance of {@code ClassLoader}.</p>
1402 *
1403 * @param classLoader The class loader whose parent class loader to return or {@code null} to return a
1404 * {@code ClassLoader} instance representing the platform's bootstrap class loader.
1405 *
1406 * @return The parent class loader of {@code classLoader}.
1407 *
1408 * @throws NullPointerException if {@code classLoader} is {@code null}.
1409 *
1410 * @see #getBootstrapClassLoaderClassName()
1411 * @see ClassLoader#getParent()
1412 */
1413 public static ClassLoader getClassLoader( final ClassLoader classLoader )
1414 {
1415 if ( classLoader == null )
1416 {
1417 return BOOTSTRAP_CLASSLOADER;
1418 }
1419
1420 if ( classLoader.getParent() != null &&
1421 !classLoader.getParent().getClass().getName().equals( getBootstrapClassLoaderClassName() ) )
1422 {
1423 return getClassLoader( classLoader.getParent() );
1424 }
1425
1426 return classLoader;
1427 }
1428
1429 /**
1430 * Gets an object of a given instance from a given scope.
1431 *
1432 * @param scope The scope to get the object from or {@code null}.
1433 * @param instance The instance of the object to get.
1434 * @param classLoader The class loader to use for creating the object.
1435 *
1436 * @return An object of {@code instance} from {@code scope} or {@code null} if no such object is found.
1437 *
1438 * @throws NullPointerException if {@code instance} or {@code classLoader} is {@code null}.
1439 * @throws InstantiationException if creating an object fails.
1440 */
1441 public Object getObject( final Scope scope, final Instance instance, final ClassLoader classLoader )
1442 throws InstantiationException
1443 {
1444 if ( instance == null )
1445 {
1446 throw new NullPointerException( "instance" );
1447 }
1448 if ( classLoader == null )
1449 {
1450 throw new NullPointerException( "classLoader" );
1451 }
1452
1453 Object object = null;
1454 final Modules model = this.getModules( classLoader );
1455
1456 if ( scope != null )
1457 {
1458 synchronized ( scope )
1459 {
1460 object = scope.getObject( instance.getIdentifier() );
1461
1462 if ( object == null )
1463 {
1464 scope.putObject( instance.getIdentifier(), instance );
1465
1466 try
1467 {
1468 object = model.createObject( instance, classLoader );
1469 }
1470 finally
1471 {
1472 if ( object != null )
1473 {
1474 object = this.createProxy( instance, object );
1475 }
1476
1477 scope.putObject( instance.getIdentifier(), object );
1478 }
1479 }
1480 else if ( object instanceof Instance )
1481 {
1482 throw new ObjectManagementException( this.getDependencyCycleMessage(
1483 ( (Instance) object ).getIdentifier() ) );
1484
1485 }
1486 }
1487 }
1488 else
1489 {
1490 try
1491 {
1492 object = model.createObject( instance, classLoader );
1493 }
1494 finally
1495 {
1496 if ( object != null )
1497 {
1498 object = this.createProxy( instance, object );
1499 }
1500 }
1501 }
1502
1503 return object;
1504 }
1505
1506 /**
1507 * Gets an object for a given location URI.
1508 *
1509 * @param specification The specification class of the object to locate.
1510 * @param location The location URI of the object to locate.
1511 * @param classLoader The class loader to use for loading locator classes.
1512 * @param <T> The type of the object.
1513 *
1514 * @return An object located at {@code location} or {@code null} if no such object is found.
1515 *
1516 * @throws NullPointerException if {@code specification}, {@code location} or {@code classLoader} is {@code null}.
1517 * @throws InstantiationException if instantiating a locator fails.
1518 * @throws ClassNotFoundException if the class of {@code specification} is not found.
1519 * @throws IOException if locating the object fails.
1520 */
1521 public <T> T getObject( final Class<T> specification, final URI location, final ClassLoader classLoader )
1522 throws InstantiationException, ClassNotFoundException, IOException
1523 {
1524 if ( specification == null )
1525 {
1526 throw new NullPointerException( "specification" );
1527 }
1528 if ( location == null )
1529 {
1530 throw new NullPointerException( "location" );
1531 }
1532 if ( classLoader == null )
1533 {
1534 throw new NullPointerException( "classLoader" );
1535 }
1536
1537 T object = null;
1538 final Locator locator = this.getLocator( classLoader, location );
1539
1540 if ( locator != null )
1541 {
1542 object = locator.getObject( specification, location );
1543 }
1544 else if ( this.isLoggable( Level.WARNING ) )
1545 {
1546 this.log( Level.WARNING, this.getMissingLocatorMessage( location ), new Exception() );
1547 }
1548
1549 return object;
1550 }
1551
1552 /**
1553 * Gets the scope implementation for a given scope identifier.
1554 *
1555 * @param classLoader The class loader to use for loading scope implementations.
1556 * @param identifier The identifier of the scope to get an implementation of.
1557 *
1558 * @return The implementation of the scope identified by {@code identifier} or {@code null} if no such
1559 * scope implementation is found.
1560 *
1561 * @throws NullPointerException if {@code classLoader} or {@code identifier} is {@code null}.
1562 * @throws InstantiationException if instantiating a scope fails.
1563 *
1564 * @see #getDefaultScope(java.lang.String)
1565 */
1566 public Scope getScope( final ClassLoader classLoader, final String identifier ) throws InstantiationException
1567 {
1568 if ( classLoader == null )
1569 {
1570 throw new NullPointerException( "classLoader" );
1571 }
1572 if ( identifier == null )
1573 {
1574 throw new NullPointerException( "identifier" );
1575 }
1576
1577 final Modules model = this.getModules( classLoader );
1578 final ClassLoader scopesLoader = getClassLoader( classLoader );
1579
1580 synchronized ( this.scopes )
1581 {
1582 Map<String, Scope> cachedScopes = this.scopes.get( scopesLoader );
1583 if ( cachedScopes == null )
1584 {
1585 cachedScopes = new HashMap();
1586 this.scopes.put( scopesLoader, cachedScopes );
1587 }
1588
1589 Scope scope = cachedScopes.get( identifier );
1590
1591 if ( scope == null )
1592 {
1593 // Bootstrap scope loading.
1594 final Specification scopeSpecification = model.getSpecification( Scope.class );
1595
1596 if ( scopeSpecification != null )
1597 {
1598 final Implementations implementations =
1599 model.getImplementations( scopeSpecification.getIdentifier() );
1600
1601 if ( implementations != null )
1602 {
1603 for ( Implementation i : implementations.getImplementation() )
1604 {
1605 if ( identifier.equals( i.getName() ) )
1606 {
1607 final Instance instance = model.getInstance( i.getIdentifier() );
1608
1609 if ( instance != null )
1610 {
1611 scope = (Scope) model.createObject( instance, classLoader );
1612 cachedScopes.put( identifier, scope );
1613 if ( this.isLoggable( Level.CONFIG ) )
1614 {
1615 this.log( Level.CONFIG, this.getMessage( "scopeInfo", new Object[]
1616 {
1617 i.getIdentifier(), identifier, scopesLoader.toString()
1618 } ), null );
1619
1620 }
1621 break;
1622 }
1623 else if ( this.isLoggable( Level.WARNING ) )
1624 {
1625 this.log( Level.WARNING, this.getMissingInstanceMessage(
1626 i.getIdentifier(), i.getName() ), new Exception() );
1627
1628 }
1629 }
1630 }
1631 }
1632 }
1633 else if ( this.isLoggable( Level.WARNING ) )
1634 {
1635 this.log( Level.WARNING, this.getMissingSpecificationMessage( Scope.class.getName() ),
1636 new Exception() );
1637
1638 }
1639 }
1640
1641 if ( scope == null )
1642 {
1643 scope = this.getDefaultScope( identifier );
1644 if ( scope != null )
1645 {
1646 cachedScopes.put( identifier, scope );
1647 if ( this.isLoggable( Level.FINE ) )
1648 {
1649 this.log( Level.FINE, this.getDefaultScopeInfoMessage( identifier, scopesLoader ), null );
1650 }
1651 }
1652 }
1653
1654 return scope;
1655 }
1656 }
1657
1658 /**
1659 * Gets the default scope implementation for a given identifier.
1660 *
1661 * @param identifier The identifier of the scope to get a default implementation of.
1662 *
1663 * @return The default implementation of the scope identified by {@code identifier} or {@code null} if no such
1664 * default implementation is available.
1665 *
1666 * @throws NullPointerException if {@code identifier} is {@code null}.
1667 *
1668 * @see #getScope(java.lang.ClassLoader, java.lang.String)
1669 */
1670 public Scope getDefaultScope( final String identifier )
1671 {
1672 if ( identifier == null )
1673 {
1674 throw new NullPointerException( "identifier" );
1675 }
1676
1677 DefaultScope defaultScope = null;
1678
1679 if ( identifier.equals( SINGLETON_SCOPE_IDENTIFIER ) )
1680 {
1681 defaultScope = new DefaultScope( new HashMap<String, Object>() );
1682 }
1683
1684 return defaultScope;
1685 }
1686
1687 /**
1688 * Gets a locator to use with a given location URI.
1689 *
1690 * @param classLoader The class loader to use for loading locator implementations.
1691 * @param location The location URI to get a locator for.
1692 *
1693 * @return The locator to use for locating objects at {@code location} or {@code null} if no such locator is
1694 * available.
1695 *
1696 * @throws NullPointerException if {@code classLoader} or {@code location} is {@code null}.
1697 * @throws InstantiationException if instantiating a locator fails.
1698 *
1699 * @see #getDefaultLocator(java.net.URI)
1700 */
1701 public Locator getLocator( final ClassLoader classLoader, final URI location ) throws InstantiationException
1702 {
1703 if ( classLoader == null )
1704 {
1705 throw new NullPointerException( "classLoader" );
1706 }
1707 if ( location == null )
1708 {
1709 throw new NullPointerException( "location" );
1710 }
1711
1712 final String scheme = location.getScheme();
1713
1714 if ( scheme != null )
1715 {
1716 final Modules model = this.getModules( classLoader );
1717 final ClassLoader locatorsLoader = getClassLoader( classLoader );
1718
1719 synchronized ( this.locators )
1720 {
1721 Map<String, Locator> cachedLocators = this.locators.get( locatorsLoader );
1722 if ( cachedLocators == null )
1723 {
1724 cachedLocators = new HashMap();
1725 this.locators.put( locatorsLoader, cachedLocators );
1726 }
1727
1728 Locator locator = cachedLocators.get( scheme );
1729
1730 if ( locator == null )
1731 {
1732 // Bootstrap locator loading.
1733 final Specification locatorSpecification = model.getSpecification( Locator.class );
1734
1735 if ( locatorSpecification != null )
1736 {
1737 final Implementations implementations =
1738 model.getImplementations( locatorSpecification.getIdentifier() );
1739
1740 if ( implementations != null )
1741 {
1742 for ( Implementation i : implementations.getImplementation() )
1743 {
1744 if ( scheme.equals( i.getName() ) )
1745 {
1746 final Instance instance = model.getInstance( i.getIdentifier() );
1747
1748 if ( instance != null )
1749 {
1750 locator = (Locator) model.createObject( instance, classLoader );
1751 cachedLocators.put( scheme, locator );
1752
1753 if ( this.isLoggable( Level.CONFIG ) )
1754 {
1755 this.log( Level.CONFIG, this.getMessage( "locatorInfo", new Object[]
1756 {
1757 i.getIdentifier(), scheme, locatorsLoader.toString()
1758 } ), null );
1759
1760 }
1761
1762 break;
1763 }
1764 else if ( this.isLoggable( Level.WARNING ) )
1765 {
1766 this.log( Level.WARNING, this.getMissingInstanceMessage(
1767 i.getIdentifier(), i.getName() ), new Exception() );
1768
1769 }
1770 }
1771 }
1772 }
1773 }
1774 else if ( this.isLoggable( Level.WARNING ) )
1775 {
1776 this.log( Level.WARNING, this.getMissingSpecificationMessage( Locator.class.getName() ),
1777 new Exception() );
1778
1779 }
1780 }
1781
1782 if ( locator == null )
1783 {
1784 locator = this.getDefaultLocator( location );
1785 if ( locator != null )
1786 {
1787 cachedLocators.put( scheme, locator );
1788 if ( this.isLoggable( Level.FINE ) )
1789 {
1790 this.log( Level.FINE, this.getDefaultLocatorInfoMessage( scheme, locatorsLoader ), null );
1791 }
1792 }
1793 }
1794
1795 return locator;
1796 }
1797 }
1798
1799 return null;
1800 }
1801
1802 /**
1803 * Gets the default locator implementation for a given location URI.
1804 *
1805 * @param location The location URI to get a default locator implementation for.
1806 *
1807 * @return The default locator implementation for {@code location} or {@code null} if no default implementation is
1808 * available for {@code location}.
1809 *
1810 * @throws NullPointerException if {@code location} is {@code null}.
1811 *
1812 * @see #getLocator(java.lang.ClassLoader, java.net.URI)
1813 */
1814 public Locator getDefaultLocator( final URI location )
1815 {
1816 if ( location == null )
1817 {
1818 throw new NullPointerException( "location" );
1819 }
1820
1821 Locator locator = null;
1822 final DefaultLocator defaultLocator = new DefaultLocator();
1823
1824 if ( defaultLocator.isLocationSupported( location ) )
1825 {
1826 locator = defaultLocator;
1827 }
1828
1829 return locator;
1830 }
1831
1832 /**
1833 * Gets the invoker of the given class loader.
1834 *
1835 * @param classLoader The class loader to use for loading invoker implementations.
1836 *
1837 * @return The invoker of the given class loader.
1838 *
1839 * @throws NullPointerException if {@code classLoader} is {@code null}.
1840 * @throws InstantiationException if instantiating a new invoker fails.
1841 */
1842 public Invoker getInvoker( final ClassLoader classLoader ) throws InstantiationException
1843 {
1844 if ( classLoader == null )
1845 {
1846 throw new NullPointerException( "classLoader" );
1847 }
1848
1849 final Modules model = this.getModules( classLoader );
1850 final ClassLoader invokersLoader = getClassLoader( classLoader );
1851
1852 synchronized ( this.invokers )
1853 {
1854 Invoker invoker = this.invokers.get( invokersLoader );
1855
1856 if ( invoker == null )
1857 {
1858 final Specification invokerSpecification = model.getSpecification( Invoker.class );
1859
1860 if ( invokerSpecification != null )
1861 {
1862 final Implementations implementations =
1863 model.getImplementations( invokerSpecification.getIdentifier() );
1864
1865 if ( implementations != null && !implementations.getImplementation().isEmpty() )
1866 {
1867 for ( Implementation i : implementations.getImplementation() )
1868 {
1869 if ( invoker == null )
1870 {
1871 final Instance invokerInstance = model.getInstance( i.getIdentifier() );
1872
1873 if ( invokerInstance != null )
1874 {
1875 invoker = (Invoker) model.createObject( invokerInstance, classLoader );
1876 this.invokers.put( invokersLoader, invoker );
1877
1878 if ( this.isLoggable( Level.CONFIG ) )
1879 {
1880 this.log( Level.CONFIG, this.getMessage( "invokerInfo", new Object[]
1881 {
1882 i.getIdentifier(), invokersLoader.toString()
1883 } ), null );
1884
1885 }
1886 }
1887 else if ( this.isLoggable( Level.WARNING ) )
1888 {
1889 this.log( Level.WARNING, this.getMissingInstanceMessage(
1890 i.getIdentifier(), i.getName() ), new Exception() );
1891
1892 }
1893 }
1894 else if ( this.isLoggable( Level.FINE ) )
1895 {
1896 this.log( Level.FINE, this.getMessage( "ignoredInvoker", new Object[]
1897 {
1898 i.getIdentifier()
1899 } ), null );
1900
1901 }
1902 }
1903 }
1904 }
1905 else if ( this.isLoggable( Level.WARNING ) )
1906 {
1907 this.log( Level.WARNING, this.getMissingSpecificationMessage( Invoker.class.getName() ),
1908 new Exception() );
1909
1910 }
1911
1912 if ( invoker == null )
1913 {
1914 invoker = new DefaultInvoker();
1915 this.invokers.put( invokersLoader, invoker );
1916 if ( this.isLoggable( Level.FINE ) )
1917 {
1918 this.log( Level.FINE, this.getMessage( "defaultInvokerInfo", new Object[]
1919 {
1920 invokersLoader.toString()
1921 } ), null );
1922
1923 }
1924 }
1925 }
1926
1927 return invoker;
1928 }
1929 }
1930
1931 /**
1932 * Gets an invocation for a given object, instance, method and arguments.
1933 *
1934 * @param object The object to invoke.
1935 * @param instance The instance of the object to invoke.
1936 * @param method The method to invoke on {@code object}.
1937 * @param arguments The arguments of the invocation or {@code null}.
1938 *
1939 * @return An invocation with {@code object}, {@code instance}, {@code method} and {@code arguments}.
1940 *
1941 * @throws NullPointerException if {@code object}, {@code instance} or {@code method} is {@code null}.
1942 * @throws InstantiationException if instantiating a new invocation fails.
1943 */
1944 public Invocation getInvocation( final Object object, final Instance instance, final Method method,
1945 final Object[] arguments ) throws InstantiationException
1946 {
1947 if ( object == null )
1948 {
1949 throw new NullPointerException( "object" );
1950 }
1951 if ( instance == null )
1952 {
1953 throw new NullPointerException( "instance" );
1954 }
1955 if ( method == null )
1956 {
1957 throw new NullPointerException( "method" );
1958 }
1959
1960 Invocation invocation = null;
1961 final ClassLoader classLoader = getClassLoader( object.getClass() );
1962 final Modules model = this.getModules( classLoader );
1963 final Specification invocationSpecification = model.getSpecification( Invocation.class );
1964
1965 if ( invocationSpecification != null )
1966 {
1967 final Implementations implementations =
1968 model.getImplementations( invocationSpecification.getIdentifier() );
1969
1970 if ( implementations != null && !implementations.getImplementation().isEmpty() )
1971 {
1972 for ( Implementation i : implementations.getImplementation() )
1973 {
1974 if ( invocation == null )
1975 {
1976 final Instance invocationInstance = model.getInstance( i.getIdentifier() );
1977
1978 if ( invocationInstance != null )
1979 {
1980 invocation = (Invocation) model.createObject( invocationInstance, classLoader );
1981 }
1982 else if ( this.isLoggable( Level.WARNING ) )
1983 {
1984 this.log( Level.WARNING, this.getMissingInstanceMessage(
1985 i.getIdentifier(), i.getName() ), new Exception() );
1986
1987 }
1988 }
1989 else if ( this.isLoggable( Level.FINE ) )
1990 {
1991 this.log( Level.FINE, this.getMessage( "ignoredInvocation", new Object[]
1992 {
1993 i.getIdentifier()
1994 } ), null );
1995
1996 }
1997 }
1998 }
1999 }
2000 else if ( this.isLoggable( Level.WARNING ) )
2001 {
2002 this.log( Level.WARNING, this.getMissingSpecificationMessage( Invocation.class.getName() ),
2003 new Exception() );
2004
2005 }
2006
2007 if ( invocation == null )
2008 {
2009 invocation = new DefaultInvocation();
2010 }
2011
2012 invocation.getContext().put( DefaultInvocation.OBJECT_KEY, object );
2013 invocation.getContext().put( DefaultInvocation.METHOD_KEY, method );
2014 invocation.getContext().put( DefaultInvocation.ARGUMENTS_KEY, arguments );
2015 invocation.getContext().put( DefaultInvocation.INSTANCE_KEY, instance );
2016 return invocation;
2017 }
2018
2019 /**
2020 * Initializes the instance.
2021 * <p>This method is called once on first usage of a new instance.</p>
2022 *
2023 * @throws InstantiationException if initialization fails.
2024 */
2025 public synchronized void initialize() throws InstantiationException
2026 {
2027 try
2028 {
2029 if ( !this.initialized )
2030 {
2031 final long t0 = System.currentTimeMillis();
2032 this.initialized = true;
2033
2034 this.listeners = null;
2035 this.modules.clear();
2036 this.invokers.clear();
2037 this.locators.clear();
2038 this.scopes.clear();
2039
2040 final List<LogRecord> bootstrapLogRecords = new LinkedList<LogRecord>();
2041 Listener bootstrapListener = new Listener()
2042 {
2043
2044 public void onLog( final Level level, final String message, final Throwable throwable )
2045 {
2046 final LogRecord record = new LogRecord( level, message );
2047 record.setThrown( throwable );
2048 bootstrapLogRecords.add( record );
2049 }
2050
2051 };
2052 this.getListeners().add( bootstrapListener );
2053
2054 final ClassLoader classLoader = getClassLoader( this.getClass() );
2055 final Modules model = this.getModules( classLoader );
2056 final Specification objectManager = model.getSpecification( ObjectManager.class );
2057 if ( objectManager == null )
2058 {
2059 throw new InstantiationException( this.getMissingSpecificationMessage(
2060 ObjectManager.class.getName() ) );
2061
2062 }
2063
2064 final Instance thisInstance = model.getInstance( this );
2065 if ( thisInstance == null )
2066 {
2067 throw new InstantiationException( this.getMissingInstanceMessage(
2068 this.getClass().getName(), this.getArtifactNameMessage() ) );
2069
2070 }
2071
2072 if ( objectManager.getScope() != null )
2073 {
2074 final Scope scope = this.getScope( classLoader, objectManager.getScope() );
2075 if ( scope == null )
2076 {
2077 throw new InstantiationException( this.getMissingScopeMessage( objectManager.getScope() ) );
2078 }
2079
2080 scope.putObject( thisInstance.getIdentifier(), this );
2081 }
2082
2083 // Bootstrap listener loading.
2084 final Specification listenerSpecification = model.getSpecification( Listener.class );
2085
2086 if ( listenerSpecification != null )
2087 {
2088 final Implementations implementations =
2089 model.getImplementations( listenerSpecification.getIdentifier() );
2090
2091 if ( implementations != null && !implementations.getImplementation().isEmpty() )
2092 {
2093 for ( Implementation i : implementations.getImplementation() )
2094 {
2095 final Instance listenerInstance = model.getInstance( i.getIdentifier() );
2096 if ( listenerInstance != null )
2097 {
2098 final Listener l = (Listener) model.createObject( listenerInstance, classLoader );
2099 this.getListeners().add( l );
2100 this.log( Level.CONFIG, this.getRegisteredListenerMessage(
2101 l.getClass().getName() ), null );
2102
2103 }
2104 else if ( this.isLoggable( Level.WARNING ) )
2105 {
2106 this.log( Level.WARNING, this.getMissingInstanceMessage(
2107 i.getIdentifier(), i.getName() ), null );
2108
2109 }
2110 }
2111 }
2112 else if ( this.isLoggable( Level.WARNING ) )
2113 {
2114 this.log( Level.WARNING, this.getMissingImplementationsMessage(
2115 listenerSpecification.getIdentifier() ), new Exception() );
2116
2117 }
2118 }
2119 else if ( this.isLoggable( Level.WARNING ) )
2120 {
2121 this.log( Level.WARNING, this.getMissingSpecificationMessage(
2122 Listener.class.getName() ), new Exception() );
2123
2124 }
2125
2126 this.getListeners().remove( bootstrapListener );
2127 bootstrapListener = null;
2128
2129 if ( !this.getListeners().isEmpty() )
2130 {
2131 for ( LogRecord logRecord : bootstrapLogRecords )
2132 {
2133 this.log( logRecord.getLevel(), logRecord.getMessage(), logRecord.getThrown() );
2134 }
2135 }
2136
2137 if ( this.isLoggable( Level.FINE ) )
2138 {
2139 this.log( Level.FINE, this.getImplementationInfoMessage(
2140 Long.valueOf( System.currentTimeMillis() - t0 ) ), null );
2141
2142 }
2143 }
2144 }
2145 catch ( final InstantiationException e )
2146 {
2147 this.listeners = null;
2148 this.modules.clear();
2149 this.invokers.clear();
2150 this.locators.clear();
2151 this.scopes.clear();
2152 this.initialized = false;
2153 throw e;
2154 }
2155 }
2156
2157 /**
2158 * Notifies registered listeners.
2159 *
2160 * @param level The level of the event.
2161 * @param message The message of the event or {@code null}.
2162 * @param throwable The throwable of the event or {@code null}.
2163 *
2164 * @throws NullPointerException if {@code level} is {@code null}.
2165 */
2166 protected void log( final Level level, final String message, final Throwable throwable )
2167 {
2168 if ( level == null )
2169 {
2170 throw new NullPointerException( "level" );
2171 }
2172
2173 if ( this.isLoggable( level ) )
2174 {
2175 for ( Listener l : this.getListeners() )
2176 {
2177 l.onLog( level, message, throwable );
2178 }
2179 }
2180 }
2181
2182 /**
2183 * Creates a proxy for a given object.
2184 *
2185 * @param instance The instance of {@code object}.
2186 * @param object The object to create a proxy for.
2187 *
2188 * @return A proxy for {@code object}.
2189 *
2190 * @throws InstantiationException if creating a proxy fails.
2191 */
2192 private Object createProxy( final Instance instance, final Object object ) throws InstantiationException
2193 {
2194 try
2195 {
2196 final ClassLoader classLoader = getClassLoader( object.getClass() );
2197 final Set<Class> interfaces = new HashSet<Class>();
2198 boolean canProxy = instance.getSpecifications() != null;
2199
2200 if ( canProxy )
2201 {
2202 for ( Specification s : instance.getSpecifications().getSpecification() )
2203 {
2204 final Class clazz = Class.forName( s.getClazz(), true, classLoader );
2205
2206 if ( !clazz.isInterface() )
2207 {
2208 canProxy = false;
2209 break;
2210 }
2211
2212 interfaces.add( clazz );
2213 }
2214 }
2215
2216 if ( canProxy )
2217 {
2218 return Proxy.newProxyInstance( classLoader, interfaces.toArray( new Class[ interfaces.size() ] ),
2219 new java.lang.reflect.InvocationHandler()
2220 {
2221
2222 public Object invoke( final Object proxy, final Method method, final Object[] args )
2223 throws Throwable
2224 {
2225 return getInvoker( classLoader ).invoke( getInvocation( object, instance, method, args ) );
2226 }
2227
2228 } );
2229
2230 }
2231
2232 return object;
2233 }
2234 catch ( final ClassNotFoundException e )
2235 {
2236 throw (InstantiationException) new InstantiationException( e.getMessage() ).initCause( e );
2237 }
2238 }
2239
2240 private String getMessage( final String key, final Object arguments )
2241 {
2242 final ResourceBundle bundle =
2243 ResourceBundle.getBundle( DefaultObjectManager.class.getName().replace( '.', '/' ) );
2244
2245 return new MessageFormat( bundle.getString( key ) ).format( arguments );
2246 }
2247
2248 private String getArtifactNameMessage()
2249 {
2250 return this.getMessage( "artifactName", null );
2251 }
2252
2253 private String getMissingSpecificationMessage( final String specification )
2254 {
2255 return this.getMessage( "missingSpecification", new Object[]
2256 {
2257 specification
2258 } );
2259
2260 }
2261
2262 private String getMissingImplementationsMessage( final String specification )
2263 {
2264 return this.getMessage( "missingImplementations", new Object[]
2265 {
2266 specification
2267 } );
2268
2269 }
2270
2271 private String getMissingImplementationMessage( final String implementationName, final String specification )
2272 {
2273 return this.getMessage( "missingImplementation", new Object[]
2274 {
2275 implementationName, specification
2276 } );
2277
2278 }
2279
2280 private String getMissingObjectInstanceMessage( final Object object )
2281 {
2282 return this.getMessage( "missingObjectInstance", new Object[]
2283 {
2284 object.toString()
2285 } );
2286
2287 }
2288
2289 private String getMissingDependencyMessage( final String dependency, final String implementation )
2290 {
2291 return this.getMessage( "missingDependency", new Object[]
2292 {
2293 dependency, implementation
2294 } );
2295 }
2296
2297 private String getMissingPropertyMessage( final String property, final String implementation )
2298 {
2299 return this.getMessage( "missingProperty", new Object[]
2300 {
2301 property, implementation
2302 } );
2303
2304 }
2305
2306 private String getMissingMessageMessage( final String message, final String implementation )
2307 {
2308 return this.getMessage( "missingMessage", new Object[]
2309 {
2310 message, implementation
2311 } );
2312
2313 }
2314
2315 private String getMissingInstanceMessage( final String implementation, final String implementationName )
2316 {
2317 return this.getMessage( "missingInstance", new Object[]
2318 {
2319 implementation, implementationName
2320 } );
2321
2322 }
2323
2324 private String getMissingObjectMessage( final String implementation, final String implementationName )
2325 {
2326 return this.getMessage( "missingObject", new Object[]
2327 {
2328 implementation, implementationName
2329 } );
2330
2331 }
2332
2333 private String getDependencyCycleMessage( final String implementation )
2334 {
2335 return this.getMessage( "dependencyCycle", new Object[]
2336 {
2337 implementation
2338 } );
2339
2340 }
2341
2342 private String getImplementationInfoMessage( final Long startMillis )
2343 {
2344 return this.getMessage( "implementationInfo", new Object[]
2345 {
2346 startMillis
2347 } );
2348
2349 }
2350
2351 private String getDefaultScopeInfoMessage( final String modelScope, final ClassLoader classLoader )
2352 {
2353 return this.getMessage( "defaultScopeInfo", new Object[]
2354 {
2355 modelScope, classLoader.toString()
2356 } );
2357
2358 }
2359
2360 private String getMissingScopeMessage( final String modelScope )
2361 {
2362 return this.getMessage( "missingScope", new Object[]
2363 {
2364 modelScope
2365 } );
2366
2367 }
2368
2369 private String getRegisteredListenerMessage( final String listener )
2370 {
2371 return this.getMessage( "listenerInfo", new Object[]
2372 {
2373 listener
2374 } );
2375
2376 }
2377
2378 private String getUnsupportedMultiplicityMessage( final Multiplicity multiplicity )
2379 {
2380 return this.getMessage( "unsupportedMultiplicity", new Object[]
2381 {
2382 multiplicity
2383 } );
2384 }
2385
2386 private String getDefaultLocatorInfoMessage( final String scheme, final ClassLoader classLoader )
2387 {
2388 return this.getMessage( "defaultLocatorInfo", new Object[]
2389 {
2390 scheme, classLoader.toString()
2391 } );
2392
2393 }
2394
2395 private String getMissingLocatorMessage( final URI location )
2396 {
2397 return this.getMessage( "missingLocator", new Object[]
2398 {
2399 location.toString()
2400 } );
2401
2402 }
2403
2404 private String getModulesReport( final Modules mods, final ClassLoader classLoader )
2405 {
2406 final StringBuilder modulesInfo = new StringBuilder();
2407 final String lineSeparator = System.getProperty( "line.separator" );
2408
2409 modulesInfo.append( classLoader );
2410
2411 if ( mods.getDocumentation() != null )
2412 {
2413 modulesInfo.append( " - " ).append( mods.getDocumentation().getText(
2414 Locale.getDefault().getLanguage() ).getValue() );
2415
2416 }
2417
2418 modulesInfo.append( lineSeparator );
2419
2420 for ( Module m : mods.getModule() )
2421 {
2422 modulesInfo.append( "\tM:" ).append( m.getName() ).append( ':' ).append( m.getVersion() ).
2423 append( lineSeparator );
2424
2425 if ( m.getSpecifications() != null )
2426 {
2427 for ( Specification s : m.getSpecifications().getSpecification() )
2428 {
2429 modulesInfo.append( "\t\t" );
2430 this.appendSpecificationInfo( s, modulesInfo ).append( lineSeparator );
2431
2432 final Implementations available = mods.getImplementations( s.getIdentifier() );
2433
2434 if ( available != null )
2435 {
2436 for ( Implementation i : available.getImplementation() )
2437 {
2438 modulesInfo.append( "\t\t\t" );
2439 this.appendImplementationInfo( i, modulesInfo ).append( "@" ).
2440 append( mods.getModuleOfImplementation( i.getIdentifier() ).getName() ).
2441 append( lineSeparator );
2442
2443 }
2444 }
2445 }
2446 }
2447
2448 if ( m.getImplementations() != null )
2449 {
2450 for ( Implementation i : m.getImplementations().getImplementation() )
2451 {
2452 modulesInfo.append( "\t\t" );
2453 this.appendImplementationInfo( i, modulesInfo ).append( lineSeparator );
2454
2455 if ( i.getImplementations() != null )
2456 {
2457 modulesInfo.append( "\t\t\t" );
2458 for ( ImplementationReference r : i.getImplementations().getReference() )
2459 {
2460 this.appendImplementationInfo(
2461 mods.getImplementation( r.getIdentifier() ), modulesInfo ).append( '@' ).
2462 append( mods.getModuleOfImplementation( r.getIdentifier() ).getName() ).
2463 append( lineSeparator );
2464
2465 }
2466 }
2467 if ( i.getSpecifications() != null )
2468 {
2469 for ( SpecificationReference s : i.getSpecifications().getReference() )
2470 {
2471 modulesInfo.append( "\t\t\tS:" ).append( s.getIdentifier() ).append( ':' ).
2472 append( s.getVersion() ).append( '@' ).append( mods.getModuleOfSpecification(
2473 s.getIdentifier() ).getName() ).append( lineSeparator );
2474
2475 }
2476 }
2477
2478 if ( i.getDependencies() != null )
2479 {
2480 for ( Dependency d : i.getDependencies().getDependency() )
2481 {
2482 modulesInfo.append( "\t\t\tD:" ).append( d.getName() ).append( ':' ).
2483 append( d.getIdentifier() );
2484
2485 if ( d.getImplementationName() != null )
2486 {
2487 modulesInfo.append( ":" ).append( d.getImplementationName() );
2488 }
2489
2490 modulesInfo.append( '@' ).append( mods.getModuleOfSpecification(
2491 d.getIdentifier() ).getName() ).append( lineSeparator );
2492
2493 final Implementations available = mods.getImplementations( d.getIdentifier() );
2494
2495 if ( available != null )
2496 {
2497 for ( Implementation di : available.getImplementation() )
2498 {
2499 modulesInfo.append( "\t\t\t\t" );
2500 this.appendImplementationInfo( di, modulesInfo ).append( "@" ).
2501 append( mods.getModuleOfImplementation( di.getIdentifier() ).getName() ).
2502 append( lineSeparator );
2503
2504 }
2505 }
2506 }
2507 }
2508
2509 if ( i.getMessages() != null )
2510 {
2511 for ( Message msg : i.getMessages().getMessage() )
2512 {
2513 modulesInfo.append( "\t\t\tM:" ).append( msg.getName() ).append( ':' ).
2514 append( msg.getTemplate().getText( Locale.getDefault().getLanguage() ).getValue() ).
2515 append( lineSeparator );
2516
2517 }
2518 }
2519
2520 if ( i.getProperties() != null )
2521 {
2522 for ( Property p : i.getProperties().getProperty() )
2523 {
2524 modulesInfo.append( "\t\t\tP:" ).append( p.getName() ).append( ':' ).
2525 append( p.getType() ).append( ':' );
2526
2527 try
2528 {
2529 modulesInfo.append( p.getJavaValue( getClassLoader( this.getClass() ) ) );
2530 }
2531 catch ( final ClassNotFoundException e )
2532 {
2533 modulesInfo.append( Level.WARNING.getLocalizedName() ).append( " " ).append( e );
2534 }
2535 catch ( final InstantiationException e )
2536 {
2537 modulesInfo.append( Level.WARNING.getLocalizedName() ).append( " " ).append( e );
2538 }
2539
2540 modulesInfo.append( lineSeparator );
2541 }
2542 }
2543 }
2544 }
2545 }
2546
2547 return modulesInfo.toString();
2548 }
2549
2550 private StringBuilder appendSpecificationInfo( final Specification s, final StringBuilder b )
2551 {
2552 b.append( "S:" ).append( s.getIdentifier() ).append( ':' ).append( s.getVersion() ).append( ':' ).
2553 append( s.getMultiplicity() ).append( ":Scope:" ).
2554 append( s.getScope() == null ? "Multiton" : s.getScope() ).append( ":Class:" ).append( s.getClazz() );
2555
2556 return b;
2557 }
2558
2559 private StringBuilder appendImplementationInfo( final Implementation i, final StringBuilder b )
2560 {
2561 b.append( "I:" ).append( i.getIdentifier() ).append( ':' ).append( i.getName() ).append( ':' ).
2562 append( i.getVersion() );
2563
2564 if ( i.getClazz() != null )
2565 {
2566 b.append( ":Class:" ).append( i.getClazz() );
2567 }
2568 if ( i.getLocation() != null )
2569 {
2570 b.append( ":Location:" ).append( i.getLocation() );
2571 }
2572
2573 return b;
2574 }
2575
2576 // SECTION-END
2577 // SECTION-START[Dependencies]
2578 // SECTION-END
2579 // SECTION-START[Properties]
2580 // SECTION-END
2581 // SECTION-START[Messages]
2582 // SECTION-END
2583 }