|
9.2. Building the Application ShellNow that you've got Spring Rich up and running, you're ready to configure the main application window. You'll see how to configure the window's command bars, including the menu bar and tool bar. You'll also learn how Spring Rich lets you invoke a centralized GUI command through any number of actionable controls, which can trigger some action, like buttons or menu items. You'll also specify a logical command group, which you can reuse in any number of grouping controls. These are controls that let you group other actionable controls, like menus or command bars. Once that soaks in, the following lab shows how to configure the main window's page area. The page will provide the central view into the RentABike inventory. 9.2.1. High-level application goalsBefore going further with implementation, let's clarify the goals of the RentABike rich client that you'll build in this lab.
Notice a few minor differences between this vision and the web-based clients that you've already used. You've already seen the splash screen. You'll also need to specify the command bars. Later, you'll see the rich validation and forms framework. In this lab, you'll focus on building the main window. 9.2.2. How do I do that?To configure your main window, you first need to define several singleton beans that hold the context for your application. As usual, you'll leverage Spring for configuration and dependency injection. As you've seen, a typical Spring Rich configuration will have three context definitions: a startup context, a root application context, and a child context for each application window. For now, focus on the root application context. A single root application context defines your logical middle tier (Example 9-4). It's also where several Spring Rich services and descriptors are defined. Typically, the middle-tier business definitions are broken out into their own file, separate from the rich client-tier presentation definitions. Example 9-4. business-layer-definitions.xml<beans> <bean name="rentABike" > <property name="storeName"><value>Keith's Bikes</value></property> </bean> </beans> You've already seen the RentABike interface. Notice this context links to the ArrayListRentABike, which allows us to build and test the application without any database support (Example 9-5). Later, you'll be able to swap this implementation with one of the database implementations. Example 9-5. com.springbook.richclient.richclient-definitions.xml<beans> <bean > <constructor-arg index="0"> <ref bean="applicationDescriptor"/> </constructor-arg> <constructor-arg index="1"> <ref bean="applicationLifecycleAdvisor"/> </constructor-arg> </bean> <bean > <property name="name"> <value>My RentABike</value> </property> <property name="version"> <value>1.0</value> </property> </bean> <bean > <property name="windowCommandBarDefinitions"> <value> classpath:com/springbook/richclient/window-command-bars.xml </value> </property> <property name="startingPageId"> <value>bikeNavigator</value> </property> </bean> You see three bean definitions:
The next set of bean definitions select implementations of common services typical of most rich client applications: Note: The component factory definition centralizes the production of Swing controls. <bean /> <bean > <property name="basenames"> <list> <value>org.springframework.richclient.application.messages</value> <value>com.springbook.richclient.messages</value> </list> </property> </bean> Note: A Spring message source lets you externalize i18n messages from Java code. <bean > <property name="basenames"> <list> <value>org.springframework.richclient.application.images</value> <value>com.springbook.richclient.images</value> </list> </property> <property name="brokenImageIndicator"> <value>classpath:/images/alert/error_obj.gif</value> </property> </bean> Note: An optional Spring Rich Client image source lets you separate hard paths from your code. <bean > <property name="theme"> <bean /> </property> </bean> The next rich client bean definition deserves special attention because it is a bean post processor. Any bean post processor defined in the context will receive a call back after another bean is instantiated by Spring. That callback allows the insertion of custom processing for those beans. Note: The optional LooksConfigurer definition lets you control the application's look and feelin this case, a jgoodies skin. The applicationObjectConfigurer post processor below processes all beans that act as factories for controls to be displayed on the screen. Set it up like this, and you'll learn more below: <bean > </bean> This applicationObjectConfigurer injects properties to visual descriptor beans. Essentially, these beans act as factories for GUI components rendering i18n messages, images, or icons. To illustrate this in action, consider the applicationDescriptor bean you defined above. After Spring instantiates this descriptor, the applicationObjectConfigurer injects it localized properties, pulling them from the configured i18n sources. In summary, the applicationObjectConfigurer gives you a powerful, consistent, automated configuration strategy for all of your GUI control factories. 9.2.2.1 Check pointTime for a check point. So far in this lab, you've created the root application context defining the business layer and several important rich client services. If you were to run your application now, by launching the RentABikeApplicationLauncher main method defined in the first lab, this is what you'd get: org.springframework.richclient.application.ConfigurationException: Unable to load window command bar definition at location: [classpath: com/springbook/richclient/window-command-bars.xml] The cause is simple. The RentABikeLifecycleAdvisor bean points to the above file for the configuration of the main window command bars, but the file doesn't yet exist. It's time to create that file so the main window will load successfully (Example 9-6). To keep things simple, you'll add a menubar with a single "File" menu for now, and a tool bar with a shared "Save" command. Example 9-6. com.springbook.richclient.window-command-bars.xml<beans> <bean > <property name="members"> <list> <ref bean="fileMenu"/> </list> </property> </bean> <bean > <property name="members"> <list> <ref bean="newMenu"/> <value>separator</value> <value>saveCommand</value> <value>propertiesCommand</value> <value>separator</value> <bean /> </list> </property> </bean> <bean > <property name="commandIds"> <list> <value>saveCommand</value> <value>propertyCommand</value> </list> </property> </bean> <bean > <property name="members"> <list> <value>placeholder:newBikeCommand</value> </list> </property> </bean> <bean > <property name="members"> <list> <ref bean="newMenu"/> <value>saveCommand</value> </list> </property> </bean> </beans> That's it! Now if you were to run your application by launching the RentABikeApplicationLauncher main method defined in the first lab, you'd get Figure 9-1. Figure 9-1. Rent-A-Bike main methodA generic application shell, with placeholders for our application-specific commands! Pretty easy, huh?! 9.2.3. What just happened?How did the framework know that the newBikeCommand should be labeled "Bike" with a "B" mnemonic and a Ctrl-B accelerator key? You certainly didn't define any of that configuration above! That leads us back to the application object configurer. Just as it can autoconfigure any control factory, it can also autoconfigure commands, pulling i18n metadata from the Spring configured message and image sources. For example, for the newBikeCommand above, the resource bundle files include the following: newBikeCommand.label=&Bike@ctrl B newBikeCommand.caption=Creates a new bike newBikeCommand.icon=bullets/blue_diamond.gif The framework handles all the configuration for you. No more manual configuration code! You saw in this lab how to define the root context of a Spring Rich powered application, and how to configure the main window, including the window's "command bars." The result? A application shell with placeholders for the commands needed by your application, ready to customize in the next lab. There's a lot going on behind the scenes to make things very convenient for you as a developer. The framework manages the entire lifecycle of your application, including opening a fully configured window populated with the command bars configured in the context file. The slick applicationObjectConfigurer autoconfigures beans for you that produce controls to be displayed on the screen, relieving you from having to configure them manually. In summary, boilerplate code is kept inside the framework, so you can focus on solving your domain problem.
|
|