001    /*
002     * Copyright 2002-2006 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.richclient.application.support;
017    
018    import java.io.IOException;
019    import java.util.Collections;
020    import java.util.HashMap;
021    import java.util.Iterator;
022    import java.util.Map;
023    
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import org.springframework.beans.factory.NoSuchBeanDefinitionException;
027    import org.springframework.binding.convert.ConversionService;
028    import org.springframework.binding.form.FieldFaceSource;
029    import org.springframework.binding.form.FormModel;
030    import org.springframework.binding.form.support.MessageSourceFieldFaceSource;
031    import org.springframework.binding.value.ValueChangeDetector;
032    import org.springframework.binding.value.support.DefaultValueChangeDetector;
033    import org.springframework.context.ApplicationContext;
034    import org.springframework.context.ApplicationContextAware;
035    import org.springframework.context.MessageSource;
036    import org.springframework.context.support.GenericApplicationContext;
037    import org.springframework.context.support.MessageSourceAccessor;
038    import org.springframework.context.support.ResourceBundleMessageSource;
039    import org.springframework.context.support.ResourceMapFactoryBean;
040    import org.springframework.core.enums.LabeledEnumResolver;
041    import org.springframework.core.enums.StaticLabeledEnumResolver;
042    import org.springframework.core.io.ClassPathResource;
043    import org.springframework.richclient.application.ApplicationPageFactory;
044    import org.springframework.richclient.application.ApplicationServices;
045    import org.springframework.richclient.application.ApplicationWindowFactory;
046    import org.springframework.richclient.application.DefaultConversionServiceFactoryBean;
047    import org.springframework.richclient.application.PageComponentPaneFactory;
048    import org.springframework.richclient.application.PageDescriptorRegistry;
049    import org.springframework.richclient.application.ServiceNotFoundException;
050    import org.springframework.richclient.application.ViewDescriptorRegistry;
051    import org.springframework.richclient.application.config.ApplicationObjectConfigurer;
052    import org.springframework.richclient.application.config.DefaultApplicationObjectConfigurer;
053    import org.springframework.richclient.command.CommandServices;
054    import org.springframework.richclient.command.config.CommandConfigurer;
055    import org.springframework.richclient.command.config.DefaultCommandConfigurer;
056    import org.springframework.richclient.command.support.DefaultCommandServices;
057    import org.springframework.richclient.factory.ButtonFactory;
058    import org.springframework.richclient.factory.ComponentFactory;
059    import org.springframework.richclient.factory.DefaultButtonFactory;
060    import org.springframework.richclient.factory.DefaultComponentFactory;
061    import org.springframework.richclient.factory.DefaultMenuFactory;
062    import org.springframework.richclient.factory.MenuFactory;
063    import org.springframework.richclient.form.binding.BinderSelectionStrategy;
064    import org.springframework.richclient.form.binding.BindingFactoryProvider;
065    import org.springframework.richclient.form.binding.swing.SwingBinderSelectionStrategy;
066    import org.springframework.richclient.form.binding.swing.SwingBindingFactoryProvider;
067    import org.springframework.richclient.form.builder.FormComponentInterceptor;
068    import org.springframework.richclient.form.builder.FormComponentInterceptorFactory;
069    import org.springframework.richclient.image.DefaultIconSource;
070    import org.springframework.richclient.image.DefaultImageSource;
071    import org.springframework.richclient.image.IconSource;
072    import org.springframework.richclient.image.ImageSource;
073    import org.springframework.richclient.security.ApplicationSecurityManager;
074    import org.springframework.richclient.security.SecurityControllerManager;
075    import org.springframework.richclient.security.support.DefaultApplicationSecurityManager;
076    import org.springframework.richclient.security.support.DefaultSecurityControllerManager;
077    import org.springframework.richclient.util.Assert;
078    import org.springframework.rules.RulesSource;
079    import org.springframework.rules.reporting.DefaultMessageTranslatorFactory;
080    import org.springframework.rules.reporting.MessageTranslatorFactory;
081    import org.springframework.rules.support.DefaultRulesSource;
082    import org.springframework.util.ClassUtils;
083    
084    /**
085     * A default implementation of the ApplicationServices (service locator) interface. This implementation allows for the
086     * direct registration of service implementations by using various setter methods (like
087     * {@link #setImageSource(ImageSource)}). Service registry entries can also be added in bulk using the
088     * {@link #setRegistryEntries(Map)} method.
089     * <p>
090     * Except in testing environments, this class will typically be instantiated in the application context and the various
091     * service implementations will be set <b>BY ID</b>. The use of service bean ids instead of direct bean references is
092     * to avoid numerous problems with cyclic dependencies and other order dependent operations. So, a typical incarnation
093     * might look like this:
094     *
095     * <pre>
096     *       &lt;bean id=&quot;applicationServices&quot;
097     *           class=&quot;org.springframework.richclient.application.support.DefaultApplicationServices&quot;&gt;
098     *           &lt;property name=&quot;applicationObjectConfigurerId&quot;&gt;&lt;idref bean=&quot;applicationObjectConfigurer&quot; /&gt;&lt;/property&gt;
099     *           &lt;property name=&quot;imageSourceId&quot;&gt;&lt;idref bean=&quot;imageSource&quot;/&gt;&lt;/property&gt;
100     *           &lt;property name=&quot;rulesSourceId&quot;&gt;&lt;idref bean=&quot;rulesSource&quot;/&gt;&lt;/property&gt;
101     *           &lt;property name=&quot;conversionServiceId&quot;&gt;&lt;idref bean=&quot;conversionService&quot;/&gt;&lt;/property&gt;
102     *           &lt;property name=&quot;formComponentInterceptorFactoryId&quot;&gt;&lt;idref bean=&quot;formComponentInterceptorFactory&quot;/&gt;&lt;/property&gt;
103     *       &lt;/bean&gt;
104     * </pre>
105     *
106     * Note the use of the <code>idref</code> form instead of just using a string value. This is the preferred syntax in
107     * order to avoid having misspelled bean names go unreported.
108     * <p>
109     * Which service implementation is returned by {@link #getService(Class)} will be determined through the following
110     * steps:
111     * <ol>
112     * <li>Consult the current registry of service implementations which have been explicitly defined through bean
113     * definition. If a registry entry was made using a bean id, this is the point at which it will be dereferenced into the
114     * actual bean implementation. So, the bean impementation will not be referenced until it is requested.</li>
115     * <li>If the service impl. is not found yet the short string name of the service' Java class in decapitalized
116     * JavaBeans property format will be used to lookup the service implementation in the current application context.<br/>
117     * If the service class is <code>org.springframework.richclient.factory.MenuFactory</code> the bean name
118     * <code>menuFactory</code> will be used to find the bean</li>
119     * <li>If the service impl. is not found yet and a default implementation can be provided, it will be constructed at
120     * that time. Default implementations are provided for essentially all services referenced by the platform.</li>
121     * </ol>
122     *
123     * @author Larry Streepy
124     */
125    public class DefaultApplicationServices implements ApplicationServices, ApplicationContextAware {
126    
127        private static final Log logger = LogFactory.getLog( DefaultApplicationServices.class );
128    
129        /** Map of services, keyed by service type (class). */
130        private final Map services = Collections.synchronizedMap( new HashMap() );
131    
132        /** Map of service types to default implementation builders. */
133        private static final Map serviceImplBuilders = new HashMap();
134    
135        /** Application context with needed bean definitions. */
136        private ApplicationContext applicationContext;
137    
138        /** ID of the ApplicationObjectConfigurer bean. */
139        private String applicationObjectConfigurerBeanId;
140    
141        /**
142         * Default Constructor.
143         */
144        public DefaultApplicationServices() {
145        }
146    
147        /**
148         * Constuct using the given application context.
149         *
150         * @param applicationContext to use for locating named services (beans)
151         */
152        public DefaultApplicationServices( ApplicationContext applicationContext ) {
153            setApplicationContext( applicationContext );
154        }
155    
156        /**
157         * Set the application context. We are ApplicationContextAware so this will happen
158         * automatically if we are defined in the context. If not, then this method should be
159         * called directly.
160         */
161        public void setApplicationContext( ApplicationContext applicationContext ) {
162            this.applicationContext = applicationContext;
163        }
164    
165        /**
166         * @return application context
167         */
168        public ApplicationContext getApplicationContext() {
169            if (applicationContext == null) {
170                    applicationContext = new GenericApplicationContext();
171            }
172            return applicationContext;
173        }
174    
175        /**
176         * Get a service of the indicated type. If no service definition for the requested
177         * type is found in the application context, then a reasonable default implementation
178         * will be created.
179         *
180         * @param serviceType Type of service being requested
181         * @return Service instance
182         * @throws ServiceNotFoundException if the service is not found and no suitable
183         *         default implementation is available.
184         */
185        public synchronized Object getService( Class serviceType ) {
186            Assert.required( serviceType, "serviceType" );
187            Object service = services.get( serviceType );
188            if( service == null ) {
189                service = getServiceForClassType(serviceType);
190                if (service == null) {
191                    service = getDefaultImplementation(serviceType);
192                }
193                if (service != null) {
194                    services.put(serviceType, service);
195                }
196            } else {
197                // Runtime derefence of refid's
198                if( service instanceof String ) {
199                    service = getApplicationContext().getBean( (String) service, serviceType );
200                    services.put( serviceType, service );
201                }
202            }
203    
204            // If we still don't have an implementation, then it's a bust
205            if( service == null ) {
206                throw new ServiceNotFoundException(serviceType);
207            }
208            return service;
209        }
210    
211        public boolean containsService( Class serviceType ) {
212            Assert.required( serviceType, "serviceType" );
213            return services.containsKey( serviceType ) || containsServiceForClassType(serviceType) || containsDefaultImplementation( serviceType );
214        }
215    
216        /**
217         * Add entries to the service registry. This is typically called from a bean
218         * definition in the application context. The entryMap parameter must be a map with
219         * keys that are either class instances (the serviceType) or the String name of the
220         * class and values that are the implementation to use for that service or an idref to
221         * a bean that is the implementation (passed as a String).
222         *
223         * @param entryMap Map of entries
224         */
225        public void setRegistryEntries( Map entryMap ) {
226            Iterator iter = entryMap.entrySet().iterator();
227    
228            while( iter.hasNext() ) {
229                Map.Entry entry = (Map.Entry) iter.next();
230                Class serviceType = null;
231                Object key = entry.getKey();
232    
233                // If the key is a String, convert it to a class
234                if( key instanceof String ) {
235                    try {
236                        serviceType = Class.forName( (String) key );
237                    } catch( ClassNotFoundException e ) {
238                        logger.error( "Unable to convert key to Class", e );
239                    }
240                } else if( key instanceof Class ) {
241                    serviceType = (Class) key;
242                } else {
243                    logger.error( "Invalid service entry key; must be String or Class, got: " + key.getClass() );
244                }
245    
246                // If we got something usable, then add the map entry
247                if( serviceType != null ) {
248                    services.put( serviceType, entry.getValue() );
249                }
250            }
251        }
252    
253        /**
254         * Set the application object configurer service implementation.
255         *
256         * @param applicationObjectConfigurer
257         */
258        public void setApplicationObjectConfigurer( ApplicationObjectConfigurer applicationObjectConfigurer ) {
259            services.put( ApplicationObjectConfigurer.class, applicationObjectConfigurer );
260        }
261    
262        /**
263         * Set the application object configurer service implementation bean id
264         *
265         * @param applicationObjectConfigurerId bean id
266         */
267        public void setApplicationObjectConfigurerId( String applicationObjectConfigurerId ) {
268            services.put( ApplicationObjectConfigurer.class, applicationObjectConfigurerId );
269        }
270    
271        /**
272         * Set the application security manager service implementation.
273         *
274         * @param applicationSecurityManager instance to use
275         */
276        public void setApplicationSecurityManager( ApplicationSecurityManager applicationSecurityManager ) {
277            services.put( ApplicationSecurityManager.class, applicationSecurityManager );
278        }
279    
280        /**
281         * Set the application security manager service implementation bean id
282         *
283         * @param applicationSecurityManagerId bean id
284         */
285        public void setApplicationSecurityManagerId( String applicationSecurityManagerId ) {
286            services.put( ApplicationSecurityManager.class, applicationSecurityManagerId );
287        }
288    
289        /**
290         * Set the <code>ApplicationWindow</code> factory service implementation
291         *
292         * @param factory
293         */
294        public void setApplicationWindowFactory( ApplicationWindowFactory factory ) {
295            services.put( ApplicationWindowFactory.class, factory );
296        }
297    
298        /**
299         * Set the <code>ApplicationWindow</code> factory service implementation bean id
300         *
301         * @param factoryId bean id
302         */
303        public void setApplicationWindowFactoryId( String factoryId ) {
304            services.put( ApplicationWindowFactory.class, factoryId );
305        }
306    
307        /**
308         * Set the <code>ApplicationPage</code> factory service implementation
309         *
310         * @param factory
311         */
312        public void setApplicationPageFactory( ApplicationPageFactory factory ) {
313            services.put( ApplicationPageFactory.class, factory );
314        }
315    
316        /**
317         * Set the <code>ApplicationPage</code> factory service implementation bean id
318         *
319         * @param factoryId bean id
320         */
321        public void setApplicationPageFactoryId( String factoryId ) {
322            services.put( ApplicationPageFactory.class, factoryId );
323        }
324    
325        /**
326         * Set the <code>PageComponentPane</code> factory service implementation bean
327         *
328         * @param factory bean id
329         */
330        public void setPageComponentPaneFactory( PageComponentPaneFactory factory ) {
331            services.put( PageComponentPaneFactory.class, factory );
332        }
333    
334        /**
335         * Set the <code>PageComponentPane</code> factory service implementation bean id
336         *
337         * @param factoryId bean id
338         */
339        public void setPageComponentPaneFactoryId( String factoryId ) {
340            services.put( PageComponentPaneFactory.class, factoryId );
341        }
342    
343        /**
344         * Set the binder selection strategy service implementation
345         *
346         * @param binderSelectionStrategy
347         */
348        public void setBinderSelectionStrategy( BinderSelectionStrategy binderSelectionStrategy ) {
349            services.put( BinderSelectionStrategy.class, binderSelectionStrategy );
350        }
351    
352        /**
353         * Set the binder selection strategy service implementation bean id
354         *
355         * @param binderSelectionStrategyId bean id
356         */
357        public void setBinderSelectionStrategyId( String binderSelectionStrategyId ) {
358            services.put( BinderSelectionStrategy.class, binderSelectionStrategyId );
359        }
360    
361        /**
362         * Set the binding factory provider service implementation
363         *
364         * @param bindingFactoryProvider
365         */
366        public void setBindingFactoryProvider( BindingFactoryProvider bindingFactoryProvider ) {
367            services.put( BindingFactoryProvider.class, bindingFactoryProvider );
368        }
369    
370        /**
371         * Set the binding factory provider service implementation bean id
372         *
373         * @param bindingFactoryProviderId bean id
374         */
375        public void setBindingFactoryProviderId( String bindingFactoryProviderId ) {
376            services.put( BindingFactoryProvider.class, bindingFactoryProviderId );
377        }
378    
379        /**
380         * Set the command services service implementation
381         *
382         * @param commandServices
383         */
384        public void setCommandServices( CommandServices commandServices ) {
385            services.put( CommandServices.class, commandServices );
386        }
387    
388        /**
389         * Set the command services service implementation bean id
390         *
391         * @param commandServicesId bean id
392         */
393        public void setCommandServicesId( String commandServicesId ) {
394            services.put( CommandServices.class, commandServicesId );
395        }
396    
397        /**
398         * Set the command configurer service implementation
399         *
400         * @param commandConfigurer
401         */
402        public void setCommandConfigurer( CommandConfigurer commandConfigurer ) {
403            services.put( CommandConfigurer.class, commandConfigurer );
404        }
405    
406        /**
407         * Set the command configurer service implementation bean id
408         *
409         * @param commandConfigurerId bean id
410         */
411        public void setCommandConfigurerId( String commandConfigurerId ) {
412            services.put( CommandConfigurer.class, commandConfigurerId );
413        }
414    
415        /**
416         * Set the button factory service implementation
417         *
418         * @param buttonFactory
419         */
420        public void setButtonFactory( ButtonFactory buttonFactory ) {
421            services.put( ButtonFactory.class, buttonFactory );
422        }
423    
424        /**
425         * Set the button factory service implementation bean id
426         *
427         * @param buttonFactoryId bean id
428         */
429        public void setButtonFactoryId( String buttonFactoryId ) {
430            services.put( ButtonFactory.class, buttonFactoryId );
431        }
432    
433        /**
434         * Set the menu factory service implementation
435         *
436         * @param menuFactory
437         */
438        public void setMenuFactory( MenuFactory menuFactory ) {
439            services.put( MenuFactory.class, menuFactory );
440        }
441    
442        /**
443         * Set the menu factory service implementation bean id
444         *
445         * @param menuFactoryId bean id
446         */
447        public void setMenuFactoryId( String menuFactoryId ) {
448            services.put( MenuFactory.class, menuFactoryId );
449        }
450    
451        /**
452         * Set the component factory service implementation
453         *
454         * @param componentFactory
455         */
456        public void setComponentFactory( ComponentFactory componentFactory ) {
457            services.put( ComponentFactory.class, componentFactory );
458        }
459    
460        /**
461         * Set the component factory service implementation bean id
462         *
463         * @param componentFactoryId bean id
464         */
465        public void setComponentFactoryId( String componentFactoryId ) {
466            services.put( ComponentFactory.class, componentFactoryId );
467        }
468    
469        /**
470         * Set the conversion service service implementation
471         *
472         * @param conversionService
473         */
474        public void setConversionService( ConversionService conversionService ) {
475            services.put( ConversionService.class, conversionService );
476        }
477    
478        /**
479         * Set the conversion service service implementation bean id
480         *
481         * @param conversionServiceId bean id
482         */
483        public void setConversionServiceId( String conversionServiceId ) {
484            services.put( ConversionService.class, conversionServiceId );
485        }
486    
487        /**
488         * Set the form component interceptor factory service implementation
489         *
490         * @param formComponentInterceptorFactory
491         */
492        public void setFormComponentInterceptorFactory( FormComponentInterceptorFactory formComponentInterceptorFactory ) {
493            services.put( FormComponentInterceptorFactory.class, formComponentInterceptorFactory );
494        }
495    
496        /**
497         * Set the form component interceptor factory service implementation bean id
498         *
499         * @param formComponentInterceptorFactoryId bean id
500         */
501        public void setFormComponentInterceptorFactoryId( String formComponentInterceptorFactoryId ) {
502            services.put( FormComponentInterceptorFactory.class, formComponentInterceptorFactoryId );
503        }
504    
505        /**
506         * Set the field face descriptor source service implementation
507         *
508         * @param fieldFaceSource
509         */
510        public void setFieldFaceSource( FieldFaceSource fieldFaceSource ) {
511            services.put( FieldFaceSource.class, fieldFaceSource );
512        }
513    
514        /**
515         * Set the field face descriptor source service implementation bean id
516         *
517         * @param fieldFaceSourceId bean id
518         */
519        public void setFieldFaceSourceId( String fieldFaceSourceId ) {
520            services.put( FieldFaceSource.class, fieldFaceSourceId );
521        }
522    
523        /**
524         * Set the icon source service implementation
525         *
526         * @param iconSource
527         */
528        public void setIconSource( IconSource iconSource ) {
529            services.put( IconSource.class, iconSource );
530        }
531    
532        /**
533         * Set the icon source service implementation bean id
534         *
535         * @param iconSourceId bean id
536         */
537        public void setIconSourceId( String iconSourceId ) {
538            services.put( IconSource.class, iconSourceId );
539        }
540    
541        /**
542         * Set the image source service implementation
543         *
544         * @param imageSource
545         */
546        public void setImageSource( ImageSource imageSource ) {
547            services.put( ImageSource.class, imageSource );
548        }
549    
550        /**
551         * Set the image source service implementation bean id
552         *
553         * @param imageSourceId bean id
554         */
555        public void setImageSourceId( String imageSourceId ) {
556            services.put( ImageSource.class, imageSourceId );
557        }
558    
559        /**
560         * Set the labeled enum resolver service implementation
561         *
562         * @param labeledEnumResolver
563         */
564        public void setLabeledEnumResolver( LabeledEnumResolver labeledEnumResolver ) {
565            services.put( LabeledEnumResolver.class, labeledEnumResolver );
566        }
567    
568        /**
569         * Set the labeled enum resolver service implementation bean id
570         *
571         * @param labeledEnumResolverId bean id
572         */
573        public void setLabeledEnumResolverId( String labeledEnumResolverId ) {
574            services.put( LabeledEnumResolver.class, labeledEnumResolverId );
575        }
576    
577        /**
578         * Set the message source service implementation
579         *
580         * @param messageSource
581         */
582        public void setMessageSource( MessageSource messageSource ) {
583            services.put( MessageSource.class, messageSource );
584        }
585    
586        /**
587         * Set the message source service implementation bean id
588         *
589         * @param messageSourceId bean id
590         */
591        public void setMessageSourceId( String messageSourceId ) {
592            services.put( MessageSource.class, messageSourceId );
593        }
594    
595        /**
596         * Set the message source accessor service implementation
597         *
598         * @param messageSourceAccessor
599         */
600        public void setMessageSourceAccesor( MessageSourceAccessor messageSourceAccessor ) {
601            services.put( MessageSourceAccessor.class, messageSourceAccessor );
602        }
603    
604        /**
605         * Set the message source accessor service implementation bean id
606         *
607         * @param messageSourceAccessorId bean id
608         */
609        public void setMessageSourceAccesorId( String messageSourceAccessorId ) {
610            services.put( MessageSourceAccessor.class, messageSourceAccessorId );
611        }
612    
613        /**
614         * Set the rules source service implementation
615         *
616         * @param rulesSource
617         */
618        public void setRulesSource( RulesSource rulesSource ) {
619            services.put( RulesSource.class, rulesSource );
620        }
621    
622        /**
623         * Set the rules source service implementation bean id
624         *
625         * @param rulesSourceId bean id
626         */
627        public void setRulesSourceId( String rulesSourceId ) {
628            services.put( RulesSource.class, rulesSourceId );
629        }
630    
631        /**
632         * Set the security controller manager service implementation
633         *
634         * @param securityControllerManager instance to use
635         */
636        public void setSecurityControllerManager( SecurityControllerManager securityControllerManager ) {
637            services.put( SecurityControllerManager.class, securityControllerManager );
638        }
639    
640        /**
641         * Set the security controller manager service implementation bean id
642         *
643         * @param securityControllerManagerId bean id
644         */
645        public void setSecurityControllerManagerId( String securityControllerManagerId ) {
646            services.put( SecurityControllerManager.class, securityControllerManagerId );
647        }
648    
649        /**
650         * Set the value change detector service imlpementation.
651         *
652         * @param valueChangeDetector instance to use
653         */
654        public void setValueChangeDetector( ValueChangeDetector valueChangeDetector ) {
655            services.put( ValueChangeDetector.class, valueChangeDetector );
656        }
657    
658        /**
659         * Set the value change detector service imlpementation bean id
660         *
661         * @param valueChangeDetectorId bean id
662         */
663        public void setValueChangeDetectorId( String valueChangeDetectorId ) {
664            services.put( ValueChangeDetector.class, valueChangeDetectorId );
665        }
666    
667        /**
668         * Set the view descriptor registry service implementation
669         *
670         * @param viewDescriptorRegistry
671         */
672        public void setViewDescriptorRegistry( ViewDescriptorRegistry viewDescriptorRegistry ) {
673            services.put( ViewDescriptorRegistry.class, viewDescriptorRegistry );
674        }
675    
676        /**
677         * Set the page descriptor registry service implementation
678         *
679         * @param pageDescriptorRegistry
680         */
681        public void setPageDescriptorRegistry( PageDescriptorRegistry pageDescriptorRegistry ) {
682            services.put( PageDescriptorRegistry.class, pageDescriptorRegistry );
683        }
684    
685        /**
686         * Set the message translator registry service implementation
687         *
688         * @param messageTranslatorFactory
689         */
690        public void setMessageTranslatorFactory( MessageTranslatorFactory messageTranslatorFactory ) {
691            services.put( MessageTranslatorFactory.class, messageTranslatorFactory );
692        }
693    
694        /**
695         * Set the message translator registry service implementation bean id
696         *
697         * @param messageTranslatorFactory
698         */
699        public void setMessageTranslatorFactoryId( String messageTranslatorFactoryId ) {
700            services.put( MessageTranslatorFactory.class, messageTranslatorFactoryId );
701        }
702    
703        /**
704         * Set the view descriptor registry service implementation bean id
705         *
706         * @param viewDescriptorRegistryId bean id
707         */
708        public void setViewDescriptorRegistryId( String viewDescriptorRegistryId ) {
709            services.put( ViewDescriptorRegistry.class, viewDescriptorRegistryId );
710        }
711    
712        /**
713         * Set the page descriptor registry service implementation bean id
714         *
715         * @param pageDescriptorRegistryId bean id
716         */
717        public void setPageDescriptorRegistryId( String pageDescriptorRegistryId ) {
718            services.put( PageDescriptorRegistry.class, pageDescriptorRegistryId );
719        }
720    
721        /**
722         * Get the implementation of a service by using the decapitalized shortname of the serviceType class name.
723         *
724         * @param serviceType
725         *            the service class to lookup the bean definition
726         * @return the found service implementation if a bean definition can be found and it implements the required service
727         *         type, otherwise null
728         * @see ClassUtils#getShortNameAsProperty(Class)
729         */
730        protected Object getServiceForClassType(Class serviceType) {
731            String lookupName = ClassUtils.getShortNameAsProperty(serviceType);
732            ApplicationContext ctx = getApplicationContext();
733            if (ctx.containsBean(lookupName)) {
734                Object bean = ctx.getBean(lookupName);
735                if (serviceType.isAssignableFrom(bean.getClass())) {
736                    if(logger.isDebugEnabled()) {
737                        logger.debug("Using bean '" + lookupName + "' (" + bean.getClass().getName() + ") for service " + serviceType.getName());
738                    }
739                    return bean;
740                }
741                else if(logger.isDebugEnabled()){
742                    logger.debug("Bean with id '" + lookupName + "' (" + bean.getClass().getName() + ") does not implement " + serviceType.getName());
743                }
744            } else if(logger.isDebugEnabled()){
745                logger.debug("No Bean with id '" + lookupName + "' found for service " + serviceType.getName());
746            }
747            return null;
748        }
749    
750    
751        /**
752         * Get the default implementation of a service according to the service type. If no
753         * default implementation is available, then a null is returned.
754         *
755         * @param serviceType Type of service requested
756         * @return Default service implementation, or null if none defined
757         */
758        protected Object getDefaultImplementation( Class serviceType ) {
759            Object impl = null;
760            ImplBuilder builder = (ImplBuilder) serviceImplBuilders.get( serviceType );
761            if( builder != null ) {
762                impl = builder.build( this );
763            }
764            return impl;
765        }
766    
767        /**
768         * Tests if the application context contains a bean definition by using the decapitalized shortname of the serviceType class name
769         * @param serviceType the service class to lookup the bean definition
770         * @return true if a bean definition is found in the current application context, otherwise false
771         *
772         * @see ClassUtils#getShortNameAsProperty(Class)
773         */
774        protected boolean containsServiceForClassType(Class serviceType) {
775            return getApplicationContext().containsBean(ClassUtils.getShortNameAsProperty(serviceType));
776        }
777    
778        /**
779         * Tests if a default implementation for the requested service type is available
780         *
781         * @param serviceType the requested service type
782         * @return true if a default implementation is available otherwise false.
783         */
784        protected boolean containsDefaultImplementation( Class serviceType ) {
785            return serviceImplBuilders.containsKey( serviceType );
786        }
787    
788        /**
789         * Internal interface used to provide default implementation builders.
790         */
791        protected interface ImplBuilder {
792            /**
793             * Build the service implementation.
794             *
795             * @param applicationServices reference to service locator
796             * @return service implementation
797             */
798            Object build( DefaultApplicationServices applicationServices );
799        }
800    
801        protected static final ImplBuilder applicationContextImplBuilder = new ImplBuilder() {
802            public Object build( DefaultApplicationServices applicationServices ) {
803                return applicationServices.getApplicationContext();
804            }
805        };
806    
807        protected static final ImplBuilder menuFactoryImplBuilder = new ImplBuilder() {
808            public Object build( DefaultApplicationServices applicationServices ) {
809                logger.info( "Creating default service impl: MenuFactory" );
810                return new DefaultMenuFactory();
811            }
812        };
813    
814        protected static final ImplBuilder buttonFactoryImplBuilder = new ImplBuilder() {
815            public Object build( DefaultApplicationServices applicationServices ) {
816                logger.info( "Creating default service impl: ButtonFactory" );
817                return new DefaultButtonFactory();
818            }
819        };
820    
821        protected static final ImplBuilder commandServicesImplBuilder = new ImplBuilder() {
822            public Object build( DefaultApplicationServices applicationServices ) {
823                logger.info( "Creating default service impl: CommandServices" );
824                return new DefaultCommandServices();
825            }
826        };
827    
828        protected static final ImplBuilder componentFactoryImplBuilder = new ImplBuilder() {
829            public Object build( DefaultApplicationServices applicationServices ) {
830                logger.info( "Creating default service impl: ComponentFactory" );
831                return new DefaultComponentFactory();
832            }
833        };
834    
835        protected static final ImplBuilder formComponentInterceptorFactoryImplBuilder = new ImplBuilder() {
836            public Object build( DefaultApplicationServices applicationServices ) {
837                logger.info( "Creating default service impl: FormComponentInterceptorFactory" );
838                return new FormComponentInterceptorFactory() {
839                    public FormComponentInterceptor getInterceptor( FormModel formModel ) {
840                        return null;
841                    }
842                };
843            }
844        };
845    
846        protected static final ImplBuilder applicationObjectConfigurerImplBuilder = new ImplBuilder() {
847            public Object build( DefaultApplicationServices applicationServices ) {
848                // First see if there is an AOC in the context, if not construct a default
849                Object impl = null;
850                String aocBeanId = applicationServices.applicationObjectConfigurerBeanId;
851                if( aocBeanId != null ) {
852                    try {
853                        impl = applicationServices.getApplicationContext().getBean( aocBeanId,
854                                ApplicationObjectConfigurer.class );
855                    } catch( NoSuchBeanDefinitionException e ) {
856                        logger.info( "No object configurer found in context under name '" + aocBeanId
857                                + "'; configuring defaults." );
858                        impl = new DefaultApplicationObjectConfigurer((MessageSource)applicationServices.getService(MessageSource.class));
859                    }
860                } else {
861                    logger.info( "No object configurer bean Id has been set; configuring defaults." );
862                    impl = new DefaultApplicationObjectConfigurer((MessageSource)applicationServices.getService(MessageSource.class));
863                }
864                return impl;
865            }
866        };
867    
868        protected static final ImplBuilder commandConfigurerImplBuilder = new ImplBuilder() {
869            public Object build( DefaultApplicationServices applicationServices ) {
870                logger.info( "Creating default service impl: CommandConfigurer" );
871                return new DefaultCommandConfigurer();
872            }
873        };
874    
875        protected static final ImplBuilder imageSourceImplBuilder = new ImplBuilder() {
876            public Object build( DefaultApplicationServices applicationServices ) {
877                logger.info( "Creating default service impl: ImageSource" );
878                try {
879                    ResourceMapFactoryBean imageResourcesFactory = new ResourceMapFactoryBean();
880                    imageResourcesFactory.setLocation(new ClassPathResource("org/springframework/richclient/image/images.properties"));
881                    imageResourcesFactory.afterPropertiesSet();
882                                    return new DefaultImageSource((Map)imageResourcesFactory.getObject());
883                            }
884                            catch (IOException e) {
885                                    return new DefaultImageSource(new HashMap());
886                            }
887            }
888        };
889    
890        protected static final ImplBuilder iconSourceImplBuilder = new ImplBuilder() {
891            public Object build( DefaultApplicationServices applicationServices ) {
892                logger.info( "Creating default service impl: IconSource" );
893                return new DefaultIconSource();
894            }
895        };
896    
897        protected static final ImplBuilder rulesSourceImplBuilder = new ImplBuilder() {
898            public Object build( DefaultApplicationServices applicationServices ) {
899                logger.info( "Creating default service impl: RulesSource" );
900                return new DefaultRulesSource();
901            }
902        };
903    
904        protected static final ImplBuilder conversionServiceImplBuilder = new ImplBuilder() {
905            public Object build( DefaultApplicationServices applicationServices ) {
906                logger.info( "Creating default service impl: ConversionService" );
907                return new DefaultConversionServiceFactoryBean().getConversionService();
908            }
909        };
910    
911        protected static final ImplBuilder binderSelectionStrategyImplBuilder = new ImplBuilder() {
912            public Object build( DefaultApplicationServices applicationServices ) {
913                logger.info( "Creating default service impl: BinderSelectionStrategy" );
914                return new SwingBinderSelectionStrategy();
915            }
916        };
917    
918        protected static final ImplBuilder FieldFaceSourceImplBuilder = new ImplBuilder() {
919            public Object build( DefaultApplicationServices applicationServices ) {
920                logger.info( "Creating default service impl: FieldFaceSource" );
921                return new MessageSourceFieldFaceSource();
922            }
923        };
924    
925        protected static final ImplBuilder bindingFactoryProviderImplBuilder = new ImplBuilder() {
926            public Object build( DefaultApplicationServices applicationServices ) {
927                logger.info( "Creating default service impl: BindingFactoryProvider" );
928                return new SwingBindingFactoryProvider();
929            }
930        };
931    
932        protected static final ImplBuilder valueChangeDetectorImplBuilder = new ImplBuilder() {
933            public Object build( DefaultApplicationServices applicationServices ) {
934                logger.info( "Creating default service impl: ValueChangeDetector" );
935                return new DefaultValueChangeDetector();
936            }
937        };
938    
939        protected static final ImplBuilder applicationSecurityManagerImplBuilder = new ImplBuilder() {
940            public Object build( DefaultApplicationServices applicationServices ) {
941                logger.info( "Creating default service impl: ApplicationSecurityManager" );
942                return new DefaultApplicationSecurityManager( true );
943            }
944        };
945    
946        protected static final ImplBuilder SecurityControllerManagerImplBuilder = new ImplBuilder() {
947            public Object build( DefaultApplicationServices applicationServices ) {
948                logger.info( "Creating default service impl: SecurityControllerManager" );
949                return new DefaultSecurityControllerManager();
950            }
951        };
952    
953        protected static final ImplBuilder viewDescriptorRegistryImplBuilder = new ImplBuilder() {
954            public Object build( DefaultApplicationServices applicationServices ) {
955                logger.info( "Creating default service impl: ViewDescriptorRegistry" );
956                BeanFactoryViewDescriptorRegistry impl = new BeanFactoryViewDescriptorRegistry();
957                impl.setApplicationContext( applicationServices.getApplicationContext() );
958                return impl;
959            }
960        };
961    
962        protected static final ImplBuilder pageDescriptorRegistryImplBuilder = new ImplBuilder() {
963            public Object build( DefaultApplicationServices applicationServices ) {
964                logger.info( "Creating default service impl: PageDescriptorRegistry" );
965                BeanFactoryPageDescriptorRegistry impl = new BeanFactoryPageDescriptorRegistry();
966                impl.setApplicationContext( applicationServices.getApplicationContext() );
967                return impl;
968            }
969        };
970    
971        protected static final ImplBuilder messageTranslatorFactoryImplBuilder = new ImplBuilder() {
972            public Object build( DefaultApplicationServices applicationServices ) {
973                logger.info( "Creating default service impl: MessageTranslatorFactory" );
974                DefaultMessageTranslatorFactory impl = new DefaultMessageTranslatorFactory();
975                impl.setMessageSource( applicationServices.getApplicationContext() );
976                return impl;
977            }
978        };
979    
980        protected static final ImplBuilder labeledEnumResolverImplBuilder = new ImplBuilder() {
981            public Object build( DefaultApplicationServices applicationServices ) {
982                logger.info( "Creating default service impl: LabeledEnumResolver" );
983                return new StaticLabeledEnumResolver();
984            }
985        };
986    
987        protected static final ImplBuilder messageSourceImplBuilder = new ImplBuilder() {
988            public Object build( DefaultApplicationServices applicationServices ) {
989                // The application context is our properly configured message source
990                logger.info( "Using MessageSource from application context" );
991                ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
992                messageSource.setBasename("org.springframework.richclient.application.messages");
993                return messageSource;
994            }
995        };
996    
997        protected static final ImplBuilder messageSourceAccessorImplBuilder = new ImplBuilder() {
998            public Object build( DefaultApplicationServices applicationServices ) {
999                // Just construct one on top of the current message source
1000                return new MessageSourceAccessor( (MessageSource) applicationServices.getService( MessageSource.class ) );
1001            }
1002        };
1003    
1004        protected static final ImplBuilder applicationWindowFactoryImplBuilder = new ImplBuilder() {
1005            public Object build( DefaultApplicationServices applicationServices ) {
1006                logger.info( "Creating default service impl: ApplicationWindowFactory" );
1007                return new DefaultApplicationWindowFactory();
1008            }
1009        };
1010    
1011        protected static final ImplBuilder applicationPageFactoryImplBuilder = new ImplBuilder() {
1012            public Object build( DefaultApplicationServices applicationServices ) {
1013                logger.info( "Creating default service impl: ApplicationPageFactory" );
1014                return new DefaultApplicationPageFactory();
1015            }
1016        };
1017    
1018        protected static final ImplBuilder pageComponentPaneFactoryImplBuilder = new ImplBuilder() {
1019            public Object build( DefaultApplicationServices applicationServices ) {
1020                logger.info( "Creating default service impl: PageComponentPaneFactory" );
1021                return new DefaultPageComponentPaneFactory();
1022            }
1023        };
1024    
1025        /**
1026         * Static initializer to construct the implementation builder map.
1027         */
1028        static {
1029            // Default service implementation builders
1030            serviceImplBuilders.put( ApplicationContext.class, applicationContextImplBuilder );
1031            serviceImplBuilders.put( ApplicationObjectConfigurer.class, applicationObjectConfigurerImplBuilder );
1032            serviceImplBuilders.put( ApplicationSecurityManager.class, applicationSecurityManagerImplBuilder );
1033            serviceImplBuilders.put( ApplicationPageFactory.class, applicationPageFactoryImplBuilder );
1034            serviceImplBuilders.put( ApplicationWindowFactory.class, applicationWindowFactoryImplBuilder );
1035            serviceImplBuilders.put( PageComponentPaneFactory.class, pageComponentPaneFactoryImplBuilder );
1036            serviceImplBuilders.put( BinderSelectionStrategy.class, binderSelectionStrategyImplBuilder );
1037            serviceImplBuilders.put( BindingFactoryProvider.class, bindingFactoryProviderImplBuilder );
1038            serviceImplBuilders.put( ButtonFactory.class, buttonFactoryImplBuilder );
1039            serviceImplBuilders.put( MenuFactory.class, menuFactoryImplBuilder );
1040            serviceImplBuilders.put( CommandServices.class, commandServicesImplBuilder );
1041            serviceImplBuilders.put( CommandConfigurer.class, commandConfigurerImplBuilder );
1042            serviceImplBuilders.put( ComponentFactory.class, componentFactoryImplBuilder );
1043            serviceImplBuilders.put( ConversionService.class, conversionServiceImplBuilder );
1044            serviceImplBuilders.put( FormComponentInterceptorFactory.class, formComponentInterceptorFactoryImplBuilder );
1045            serviceImplBuilders.put( FieldFaceSource.class, FieldFaceSourceImplBuilder );
1046            serviceImplBuilders.put( IconSource.class, iconSourceImplBuilder );
1047            serviceImplBuilders.put( ImageSource.class, imageSourceImplBuilder );
1048            serviceImplBuilders.put( LabeledEnumResolver.class, labeledEnumResolverImplBuilder );
1049            serviceImplBuilders.put( MessageSource.class, messageSourceImplBuilder );
1050            serviceImplBuilders.put( MessageSourceAccessor.class, messageSourceAccessorImplBuilder );
1051            serviceImplBuilders.put( RulesSource.class, rulesSourceImplBuilder );
1052            serviceImplBuilders.put( SecurityControllerManager.class, SecurityControllerManagerImplBuilder );
1053            serviceImplBuilders.put( ValueChangeDetector.class, valueChangeDetectorImplBuilder );
1054            serviceImplBuilders.put( ViewDescriptorRegistry.class, viewDescriptorRegistryImplBuilder );
1055            serviceImplBuilders.put( PageDescriptorRegistry.class, pageDescriptorRegistryImplBuilder );
1056            serviceImplBuilders.put( MessageTranslatorFactory.class, messageTranslatorFactoryImplBuilder );
1057        }
1058    }