Announcement Announcement Module
Collapse
No announcement yet.
Migrating Existing App to Spring Rich Client Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Migrating Existing App to Spring Rich Client

    Hi guys,

    As you may know, I have been lurking around these forums and tinkering with Spring Rich Client for a couple of months now. Recently, I took a small use case from our business and implemented it from scratch using Spring Rich Client. It worked great but it was basically a proof of concept to show my boss (i.e. proof that Spring Rich Client is better than using our existing rich client architecture).

    Now we want to start converting an existing Swing application to use Spring Rich Client. I would prefer to do this conversion in stages, adding various Spring Framework and Spring Rich Client features/services one by one. For example, I would like to start by introducing IOC to ease the wiring of collaborators. Next, I want to get beans like Petclinic's messageSource, imageResourcesFactory, imageSource, applicationObjectConfigurer and iconSource working. Finally, I want to add Spring Rich Client's Views, Forms and Commands support. Is this a good approach? Is there a better migration path?

    I started off by adding the various Petclinic context files to my project. Then I starting modifying them and commented out a bunch of settings to try to get the container bootstrapped. One of the settings I commented out was the startingPageId setting because I don't want to introduce Spring Rich Client views right away. Unfortunately, upon startup, the container complained that this setting was required. How can I use Spring Rich Client without setting a startingPageId? I will eventually set it but for now I want to use our existing view classes and view navigation.

  • #2
    Joe,

    just put anything in "startingPageId" as long as you don't use any of the window/page/view system this won't matter. I have a similar app where 90% of it is coded in an old framework I developed years ago and I'm slowly migrating over to Spring Rich.

    Ollie

    Comment


    • #3
      Thanks for the reply Ollie.

      Originally posted by oliverhutchison
      just put anything in "startingPageId"
      How's this?:
      Code:
      <property name="startingPageId">
          <value>dummy</value>
      </property>
      Originally posted by oliverhutchison
      I have a similar app where 90% of it is coded in an old framework I developed years ago and I'm slowly migrating over to Spring Rich.
      Would you mind posting a snippet the ApplicationContext "bootstrapping" code that you are using in that app? Did you use ApplicationLauncher or some other mechanism like BeanFactoryBootstrap or SingletonBeanFactoryLocator? I'm a bit reluctant to use either of the latter two. They seem to be a little bit too invasive (the Javadocs say so too). However, AFAIK, ApplicationLauncher seems to depend on Spring Rich Client's window/page/view system. I don't want to use the window/page/view system just yet.

      Comment


      • #4
        Joe,

        this is exactly what I use. You'll need to modify some parts to suit your enviroment.

        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
        	"http&#58;//www.springframework.org/dtd/spring-beans.dtd">
        <!-- $Id&#58; richclient-application-context.xml,v 1.3 2004/10/11 00&#58;23&#58;15 oliverh Exp $ -->
        <beans>
        	
        	<bean id="application" 
        		class="org.springframework.richclient.application.Application">
        		<constructor-arg index="0">
        			<ref bean="applicationDescriptor"/>
        		</constructor-arg>
        		<constructor-arg index="1">
        			<ref bean="applicationAdvisor"/>
        		</constructor-arg>
        	</bean>
        	
          <bean id="applicationAdvisor" 
            class="org.springframework.richclient.application.config.DefaultApplicationLifecycleAdvisor">
            <property name="startingPageId">
              <value>applicationAdvisor</value>
            </property>
          </bean>
        	
        	<bean id="applicationDescriptor" 
        		class="org.springframework.richclient.application.ApplicationDescriptor">
        		<property name="version">
        			<value>1.0</value>
        		</property>
        		<property name="buildId">
        			<value>20041025001</value>
        		</property>
        	</bean>
        	
        	<bean id="applicationObjectConfigurer"
        		class="org.springframework.richclient.application.config.DefaultApplicationObjectConfigurer">
        		<constructor-arg index="0">
        			<ref bean="messageSource"/>
        		</constructor-arg>
        		<constructor-arg index="1">
        			<ref bean="imageSource"/>
        		</constructor-arg>
        		<constructor-arg index="2">
        			<ref bean="iconSource"/>
        		</constructor-arg>
        	</bean>
        		
        	<bean id="applicationEventMulticaster" 
        		class="org.springframework.context.event.SimpleApplicationEventMulticaster"/>
        		
        	<bean id="componentFactory" 
        		class="org.springframework.richclient.factory.DefaultComponentFactory">
        		<property name="iconSource">
        			<ref bean="iconSource"/>
        		</property>
        	</bean>
        	
          <bean id="propertyEditorRegistry" 
            class="org.springframework.richclient.application.support.DefaultPropertyEditorRegistry">
            <property name="propertyEditors">
              <list>
                <props>
                  <prop key="objectClass">ourcommunity.util.DateRange</prop>
                  <prop key="propertyEditorClass"> 
                    ourcommunity.admin.util.DateRangePropertyEditor</prop>
                </props>
                <props>
                  <prop key="objectClass">java.util.Date</prop>
                  <prop key="propertyEditorClass"> 
                    ourcommunity.admin.util.DatePropertyEditor</prop>
                </props>
              </list>
            </property>
          </bean>	
        	
        	<bean id="messageSource" 
        		class="org.springframework.context.support.ResourceBundleMessageSource">
        		<property name="basenames">
        			<list>
        				<value>org.springframework.richclient.application.messages</value>
        				<value>ourcommunity.admin.util.rcp.messages</value>
        			</list>
        		</property>
        	</bean>
        	
        	<bean id="imageResourcesFactory" 
        		class="org.springframework.context.support.ResourceMapFactoryBean">
        		<property name="locations">
        			<list>
        				<value>classpath&#58;org/springframework/richclient/image/images.properties</value>
        			</list>
        		</property>
        		<property name="resourceBasePath">
        			<value>images/</value>
        		</property>
        	</bean>
        	
        	<bean id="imageSource" 
        		class="org.springframework.richclient.image.DefaultImageSource">
        		<constructor-arg index="0">
        			<ref bean="imageResourcesFactory"/>
        		</constructor-arg>
        		<property name="brokenImageIndicator">
        			<value>images/alert/error_obj.gif</value>
        		</property>
        	</bean>
        	
        	<bean id="iconSource" 
        		class="org.springframework.richclient.image.DefaultIconSource">
        		<constructor-arg index="0">
        			<ref bean="imageSource"/>
        		</constructor-arg>
        	</bean>
        	
        	<bean id="formComponentInterceptorFactory" 
        		class="org.springframework.richclient.form.builder.support.ChainedInterceptorFactory">
        		<property name="interceptorFactories">
        			<list>
        				<bean 
        					class="org.springframework.richclient.form.builder.support.ColorValidationInterceptorFactory">
        					<property name="errorColor">
        						<value>255,245,245</value>
        					</property>
        				</bean>
        				<bean 
        					class="org.springframework.richclient.form.builder.support.OverlayValidationInterceptorFactory" 
        					/>
        				<bean 
        					class="org.springframework.richclient.text.TextComponentPopupInterceptorFactory" 
        					/>
        			</list>
        		</property>
        	</bean>
        </beans>
        for loading I use ClassPathXmlApplicationContext :

        Code:
        new ClassPathXmlApplicationContext&#40;
                    "/appcontext/richclient-application-context.xml"&#41;;
        HTH

        Ollie

        Comment


        • #5
          Thanks again. It looks like I was sort of on the right track (my context file looks almost identical to yours). The tip about the fake startingPageId is handy...thanks!

          Am I correct in assuming that you show your custom (i.e. not Spring Rich Client) main window just after you execute "new ClassPathXmlApplicationContext()"?

          Also, since you are not using Spring Rich Client's window/page/view system am I correct in assuming that you are doing some of your collaborator wiring/lookup via Application.services().getApplicationContext() instead of using 100% dependency injection? Keith seemed to indicate that you might need to do that with legacy code in this topic: http://forum.springframework.org/showthread.php?t=10849.
          Last edited by robyn; May 14th, 2006, 05:58 PM.

          Comment


          • #6
            Am I correct in assuming that you show your custom (i.e. not Spring Rich Client) main window just after you execute "new ClassPathXmlApplicationContext()"?
            Yes. As part of the app startup sequence.

            Also, since you are not using Spring Rich Client's window/page/view system am I correct in assuming that you are doing some of your collaborator wiring/lookup via Application.services().getApplicationContext() instead of using 100% dependency injection? Keith seemed to indicate that you might need to do that with legacy code in this topic: http://forum.springframework.org/sho...icationcontext.
            No, I don't access it via Application.services() - I keep a copy when I create it, but it's much the same thing. I do do some lookup but I've done my best to try and keep the Spring Rich code totaly isolated from the old code base so there's actualy not a lot of interaction. I have a set of classes that take Spring Rich forms and adapt them to my in house "Editor" interface.

            Ollie
            Last edited by robyn; May 14th, 2006, 06:00 PM.

            Comment


            • #7
              Originally posted by oliverhutchison
              No, I don't access it via Application.services() - I keep a copy when I create it, but it's much the same thing. I do do some lookup but I've done my best to try and keep the Spring Rich code totaly isolated from the old code base so there's actualy not a lot of interaction. I have a set of classes that take Spring Rich forms and adapt them to my in house "Editor" interface.
              Sorry for all these messages :oops:. If I'm interpreting your response correctly I believe you're saying that your old code base does NOT interact with or use any of the Spring Rich Client beans like applicationDescriptor, applicationObjectConfigurer, componentFactory, propertyEditorRegistry, messageSource, imageResourcesFactory, imageSource, etc? In other words, only your new code (or mostly only your new code) is taking advantage of these services?

              Comment


              • #8
                In other words, only your new code (or mostly only your new code) is taking advantage of these services?
                Yes. A large amout of the old code was generated using a GUI bilder so it's not easy to modify.

                Personaly I'd like to use more of the Spring Rich services but I just don't have the time to modify and test all of the existing forms.

                Ollie

                Comment


                • #9
                  Ollie (and Keith if you're monitoring this topic), do you think it's okay, short term, if I use Application.services().getApplicationContext() sparingly in my legacy code until I refactor it to use dependency injection?

                  Originally posted by oliverhutchison
                  I have a set of classes that take Spring Rich forms and adapt them to my in house "Editor" interface.
                  So I could modify my existing in-house views to contain Spring Rich forms?

                  Comment


                  • #10
                    This is very interesting topic -- thanks Cyboc and Oliver. I have same problem. I am migrating legacy swing app.

                    Curious Oliver, how many views you have in legacy app. I mean, is it big app? How many guys on your team? Just curious. Wondering if Spring and Spring Rich Client helps dividing task over many developers.

                    And KEITH - You have any advice for how to approaching migration from Swing to Spring Rich Client?

                    Comment


                    • #11
                      Ollie (and Keith if you're monitoring this topic), do you think it's okay, short term, if I use Application.services().getApplicationContext() sparingly in my legacy code until I refactor it to use dependency injection?
                      My advice - do it if it makes sense. What are the beans that you need to access? If they're not Spring Rich related I'd be putting them into a different app context and access them through that.

                      During migrating you're never going to have an ideal setup as you need to juggle the needs/interfaces to 2 possibly quite different frameworks. I've found that by creating a set of classes that adapt Spring Rich to my old framework a lot of the pain has been reduced as I can continue to use my existing windows/page/editor management system but I get to use Spring Rich for forms and control creation. This also keeps risk at a manageable level as you can then chip away at the migration piecemeal.

                      So I could modify my existing in-house views to contain Spring Rich forms?
                      Why not? The Spring Rich form interface is so simple it shouldn't be to hard to adapt it, but, I've not seen you old framework ;-)

                      Ollie
                      [/code]

                      Comment


                      • #12
                        Stefano,

                        The app's not huge but as I'm the only person maintaining it's big enough for me not to not want to attempt a complete overall. In fact, as it's fully functional, from a business point of view, I couldn't really justify spending the time converting it anyway.

                        Ollie

                        Comment


                        • #13
                          Originally posted by oliverhutchison
                          What are the beans that you need to access?
                          Our legacy code has a number of MVC triads, arranged hierarchically (i.e HMVC - see this topic for more details on HMVC). Each MVC triad can be instantiated multiple times. For example, let's say we have a triad for entering a new customer. Well, what often happens is our users will be part way through entering a new customer when they get a phone call that causes them to simultaneously start entering another new customer. In this case, we would need two instances of that triad.

                          The model classes in these triads currently access a business facade via JNDI -- in other words, pretty standard, ugly J2EE orthodox architecture...yuck. We also use a few singletons here and there to do miscellaneous lookups and to resolve some dependencies -- again, yuck. We're slowly refactoring this mess to use Spring Framework's various features, especially dependency injection and the nice support for various peristence implementations. We've also decided that we really don't need the complexity of three tier so we are converting to a standalone app.

                          Refactoring the persistence layer is actually fairly easy so far. Refactoring the app to use dependency injection is not so easy so far. We have a lot of cases where ClassA instantiates his collaborator ClassB, who instantiates his collaborator ClassC, etc. And as mentioned above, we also use singletons in some collaborations. It would be nice to have the container instantiate the classes and wire the collaborations through dependency injection.

                          As for Application.services().getApplicationContext(), I thought that for now, we could use it to do things like allow a model instance to lookup it's business layer facade. Of course, I would like the container to do this for me through dependency injection but it would require quite a bit of refactoring. We want to take baby steps right now.

                          I was also thinking that we could use Application.services().getApplicationContext() to get resources like messages, images, icons, etc.

                          Originally posted by oliverhutchison
                          If they're not Spring Rich related I'd be putting them into a different app context and access them through that.
                          I assume you mean beans that are Spring Framework related (as opposed to Spring Rich Client related) like DAOs, business layer facades, datasources, etc? If so, I guess you're recommending putting Spring Rich Client beans in one context and Spring Framework beans in another context (like in Petclinic where there are separate "richclient-application-context.xml" and "business-layer-context.xml" files)?

                          Now where I'm somewhat confused is, to minimize initial refactoring effort with my current achitecture, should I be loading both xml files into the same ApplicationContext (like what Petclinic does in PetClinicStandalone.java)? Or should I load them into separate ApplicationContexts? Your quote above seems to indicate separate ApplicationContext instances.


                          Originally posted by oliverhutchison
                          During migrating you're never going to have an ideal setup as you need to juggle the needs/interfaces to 2 possibly quite different frameworks. I've found that by creating a set of classes that adapt Spring Rich to my old framework a lot of the pain has been reduced as I can continue to use my existing windows/page/editor management system but I get to use Spring Rich for forms and control creation. This also keeps risk at a manageable level as you can then chip away at the migration piecemeal.
                          I agree. We have a lot of good code that works great right now. I don't want to break it all at once. We just want to refactor bit by bit so that eventually the system is more extendable and maintainable.
                          Last edited by robyn; May 14th, 2006, 06:01 PM.

                          Comment


                          • #14
                            As for Application.services().getApplicationContext(), I thought that for now, we could use it to do things like allow a model instance to lookup it's business layer facade. Of course, I would like the container to do this for me through dependency injection but it would require quite a bit of refactoring. We want to take baby steps right now.
                            I'd be inclined to refactory your code so that it access the business facades using a service locator that delegates to an application context where needed and JNDI where needed. Once this is done you can then work through one service at a time converting over to DI.

                            Ollie

                            Comment


                            • #15
                              Originally posted by oliverhutchison
                              I'd be inclined to refactory your code so that it access the business facades using a service locator that delegates to an application context where needed and JNDI where needed.
                              If I use Application.services().getApplicationContext() in the way I discussed (i.e. to lookup up business facades), is it necessary to make a separate service locator? I mean, isn't Application.services().getApplicationContext() sort of acting like a service locator for me in this case? Then in the ApplicationContext that it returns, I could initially use say SimpleRemoteStatelessSessionProxyFactoryBean to expose my existing session bean business facades and then slowly convert them to POJO business facades. Don't know if this makes any sense.

                              Comment

                              Working...
                              X