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