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    }