Announcement Announcement Module
Collapse
No announcement yet.
Integrating GWT client/server RPC app with Spring Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Integrating GWT client/server RPC app with Spring

    We have a Tomcat-based Google Web Toolkit (GWT) application that we are looking to scale. Our domain model is done with POJOs that we transmit back and forth between client/server using GWT’s Java serialization abilities. On the client side we have a decent separation between model and view. We then persist the model using XML on the server.

    For authentication we are using Tomcat realms with LDAP.

    We want to integrate Hibernate for persistence of the POJO model.

    I’ve been reading about all that Spring has to offer and it’s a bit overwhelming. From what I can tell, since our application sends parts of the model the client, I’m not sure that some of the traditional web MVC stuff is useful for us, since our app is more of client/server RPC. The IoC, DAO, and ORM stuff looks really useful.

    Anyone have any insight into how we can make the most of Spring?

    Thanks,
    C

  • #2
    We've been having a similar situation with an application in which, we have a lot of entities in the server side and we also need the same models in the client with GWT. Here is what we've done:

    (Model and Entity are just exchangeable terms with no specific meaning, we just separated to them to specify the layer)

    • On the Server Side: We have the entities are integrated into Hibernate using all the functionality through Spring and other services.
    • On the Client Side: We decided to create POJO's that are just alike the entities on the server side with complete relationship depth and dependencies of the models to each other. To be more specific take "CustomerEntity" as a sample that has also some relations with "OrderEntity" and "CityEntity". So, we just add some classes in the client package to be just the equivalent of the entities ad "CustomerModel", "OrderModel", and "CityModel". Actually, models and entities are the same but apart to let GWT do what it wants with them and not interfere with the server side logic.
    • On the Service Side: Some utility classes were implemented to do the converting process of the "models" to "entities". This could be easily done through Reflection API and Generics. Also, I just presumed that we have integrated GWT with Spring Web Controllers so that the business logic is available in GWT Service layer.

    So, now, when an RPC calls a service, first, the model is gathered in the GWT Service layer, then converted to the corresponding entity with exact conversion policies that could be specified along with its relations data. Then, the entity is given to the service layers in Spring taking care of the logic. When the logic is finished, the reverse conversion could be done if it is necessary to navigate a specific result to the client side. In this method, we always use the "models" in the client side in GWT. I believe some redundancy have been forced to the development but I believe it is worth it. Specially, if you would have some generators for the code.

    Hope I clarified the idea.

    Comment


    • #3
      Integrating GWT client/server RPC app with Spring

      Hi behrooznobakht,
      What you mention sounds similar to what we are trying to do. What we want to do thought is use the same POJO classes on all tiers so we don't need to have different version of these classes for client/server/persistence.

      Client Side: GWT complies the class definitions into javascript and GWT RPC serialized these
      Server side: POJOs are serialized into DB by hibernate

      I'm hoping that this is possible. We already use the same POJOs classes on both client and server so I know that is possible. Serializing these POJOs into hibernate looks possible too. The only constraint with this is that for GWT, the POJOs need to:

      1) be defined in a package or sub-package that complies with GWT's client naming conventions. For example, we are using com.somecompanyname.client.common, for classes that are common to both client and server. This way the GWT compiler picks up on the client package and compiles them.

      2) implement com.google.gwt.user.client.rpc.IsSerializable

      Maybe 2) is the reason that you want different copies of the classes. We're going to try and do it with only one version of our classes, but if we can't then I guess we'll need to use refection and have some glue to create hibernate-able POJOs from our GWT serializable POJOs.

      Thanks,
      c

      Comment


      • #4
        What we want to do thought is use the same POJO classes on all tiers so we don't need to have different version of these classes for client/server/persistence.
        This is certainly the correct approach. What behrooznobakht's team has done is... not good, to say the least. There is no need to duplicate your domain entities. Reflection? Brrr... Domain entities are supposed to be exchanged between the tiers. Read the beginning of this thread:

        http://forum.springframework.org/showthread.php?t=64862

        Also, consider packaging classes by functionality, not by type. That should give you a general idea about the architecture... Regarding using Hibernate... Make sure your domain (entities) model maps to your database schema well. Otherwise, you may be adding an additional unnecessary layer of complexity. Using Spring JDBC support is often a good alternative: simple, and efficient. Of course, ORM can be a great solution if the object model maps to the database schema nicely and easily.

        HTH,
        Constantine

        Comment


        • #5
          First, thank you for your notes. However, let's make somehow more detailed on this as it is totally interesting for me personally.

          Consider this as the project scenario: We have a base architecture which is built on the useful techs such as Spring, JSF, Hibernate; along with some core functionality on generics and the required services for every project. So it provides us with the grounds that business-specific projects may need.

          Now, there is a project that has two major user interfaces parts. One part is used by administrators and central operators that has been implemented using something like JSF and the server-side technologies. And, another part, that is used by operators usually called the application desktop. The decision was to do the part-one section with JSF and the part-two with GWT to make it easier and friendlier for the operators as they need to do their job like a desktop application can server them.

          On one side, I totally agree with Constantine that duplicating the models in GWT and the service would be a waste and a harm to the project. On the other, and architecturally speaking, usually we have software architecture of a kind that has been developed to be reused and extended in several projects. In this case, when you face such a problem, what would you do? Yet the architecture should be consistent and continue to work with the classic entity-hibernate-method, now you need the same functionality in GWT layer.

          In this regard, maybe I just personally guessed that this post was exactly the same as our situation. And, yes you're right that if we only are using GWT on the project and no other view technology, that's the better idea to build up the application on the models that are both compatible with GWT and Hibernate and with no redundancy.

          But, if you'd have an application that should be developed both with something like JSF and GWT at the same for its own reasons, I'd believe there would be some redundancy that should be faced with.

          And, Christoph, IsSerializable is no longer necessary; GWT now understands java.io.Serializable.

          Thank you Constantine for your comments; I'd be happy for more.

          Comment


          • #6
            Originally posted by behrooznobakht View Post
            On one side, I totally agree with Constantine that duplicating the models in GWT and the service would be a waste and a harm to the project. On the other, and architecturally speaking, usually we have software architecture of a kind that has been developed to be reused and extended in several projects. In this case, when you face such a problem, what would you do?
            You do the same. in fact, your business components - unless they are totally specific to one particular application - should always be organized and packaged as separate re-usable modules. That means, they should always live outside any application and be added to each application as dependencies. each such component must provide everything that defines the functional domain it represents: domain entities, service APIs, and default implementations. This allows applications to reuse the domain entity objects in its front-end and middle-tier, use the out-of-the box service implementations, or, if necessary, to provide their own app-specific implementations of the service APIs (and/or DAOs for the existing service implementation if it uses DAOs and provides the public APIs for them.)

            Comment


            • #7
              Thanks and good as I believe we're on the same track :-)

              However, I am still on my point of view that in a case such as gathering JSF and GWT in one application in which the model objects are required in both of view layers, there would be some forced redundancy that should be dealt with.

              It is a nice discussion and thanks for sharing.

              Comment


              • #8
                I was recently facing the temptation of duplicating POJOs used for GWT. The reason was GWT limitations (objects used in RPC can't collaborate with non serializable objects).
                But Actually, such a duplication could have lead me to GWT abandon. I join constv point of view, code duplication is a worst practice I don't want to ... practice.

                The solution I am trying (don't have enough experience to evaluate for now) is having two libraries:
                • one for Data Transfer Objects (DTOs) responsible for data holding
                • one for business objects inheriting from (not duplicating) DTOs and responsible for business logic.
                DTOs are used for GWT-RPC on client and server side
                Business objects remain on server side, managed by Spring of course

                Christoph, I've just posted a tutorial that could save you a lot of time plugging all the parts together (GWT, Spring, Hibernate, ...). It does not contain the inheritence I just mentioned . The reason are:
                • I wrote it a few weeks ago and I haven't updated it
                • Business functionalities exposed do not require collaboration with non serializable objects

                Comment


                • #9
                  Integrating GWT client/server RPC app with Spring

                  Hi,

                  I'm new to GWT and I was trying to get a simple app that will use GWT+Spring+Maven. I was able to find a suitable example on the internet for GWT+Spring+Maven, that also work. THe issue is that when I'm trying to define new beans and inject them in the exsiting GWT ones, the DI doesn't work as expected. I am getting no errors though, just null values.

                  The example was taken from internet. I had to tweak it a little bit to work properly. To that app I was trying to add a BO layer and a DAO layer.

                  Any suggestions how could I register&inject those beans (myObjectDAO and myObjectBO) into "quoteService"? "quoteService" bean is registered and injected properly in "quoteController". I do have the setters properly in place for the properties in the bean class, otherwise spring would complained.
                  Thank you.

                  service-context.xml
                  Code:
                  <?xml version="1.0" encoding="UTF-8"?>
                  <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "...">
                  <beans>
                     <bean id="quoteService" class="com.totsp.sample.client.QuoteServiceImpl">
                          <property name="myObjBO">
                              <ref bean="myObjectBO" /> 
                          </property>
                      </bean>
                  	<bean id="salesproServicePlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                          <property name="ignoreUnresolvablePlaceholders" value="true"/>
                          <property name="location">
                              <value>classpath:service-placeholder.properties</value>
                          </property>
                      </bean>
                      
                     	<bean id="myObjectDAO" class="com.totsp.sample.dao.MyObjectDAOImpl"> 
                     		<!--       
                     		<property name="sqlMapClient">
                     			<ref bean="sqlMapClient" />    
                   		</property>
                   		-->
                     	</bean>
                     	
                     	<bean id="myObjectBO" class="com.totsp.sample.bo.MyObjectBOImpl">
                          <property name="myObjectDAO">
                     			<ref bean="myObjectDAO" />    
                   		</property>
                      </bean>    
                  </beans>
                  spring-servlet.xml
                  Code:
                  <?xml version="1.0" encoding="UTF-8"?>
                  <beans xmlns="..."
                      xmlns:xsi="..."
                      xsi:schemaLocation="...">
                  
                      <!-- The application context definition for the DispatcherServlet -->
                  
                      <!-- Maps the request through to a concrete controller instance -->
                      <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
                          <property name="mappings">
                              <value>
                              /**/quote.rpc=quoteController
                              </value>
                          </property>
                      </bean>
                  
                      <!-- GwtRpcController wraps our service in order to decode the incoming -->
                      <!-- request then delegates processing of the call to the POJO service -->
                      <!-- and then encodes the return value forwarding the response. -->
                      <bean id="quoteController" class="com.totsp.sample.client.GwtRpcController">
                          <property name="remoteService">
                              <ref bean="quoteService" /> 
                          </property>
                      </bean>
                  </beans>
                  web.xml
                  Code:
                  <?xml version="1.0" encoding="UTF-8"?>
                  
                  <web-app version="2.4" xmlns="..."
                  	xmlns:xsi="..."
                  	xsi:schemaLocation="...">
                  	<display-name>Sample</display-name>
                  
                  	<welcome-file-list>
                  		<welcome-file>index.html</welcome-file>
                  	</welcome-file-list>
                  
                  	<context-param>
                  		<param-name>contextConfigLocation</param-name>
                  		<param-value>
                  			classpath:service-context.xml,
                  			classpath:spring-servlet.xml
                  		</param-value>
                  	</context-param>
                  
                  	<listener>
                  		<listener-class>
                  			org.springframework.web.context.ContextLoaderListener
                  		</listener-class>
                  	</listener>
                  	<!-- 
                  	<listener>
                  		<listener-class>
                  			org.springframework.web.context.request.RequestContextListener
                  		</listener-class>
                  	</listener>
                   -->
                  	<servlet>
                  		<servlet-name>spring</servlet-name>
                  		<servlet-class>
                  			org.springframework.web.servlet.DispatcherServlet
                  		</servlet-class>
                  		<load-on-startup>1</load-on-startup>
                  	</servlet>
                  
                      <servlet-mapping>
                          <servlet-name>spring</servlet-name>
                          <url-pattern>*.rpc</url-pattern>
                      </servlet-mapping>
                  	
                  </web-app>

                  Comment


                  • #10
                    sorry for not been able to add the urls, but been first time the app wouldn't allowed me to do it.

                    The example that I modified was taken from http://technophiliac.wordpress.com/2...g-in-its-step/

                    Thanks

                    Comment


                    • #11
                      Originally posted by Cristian View Post
                      I'm trying to define new beans and inject them in the exsiting GWT ones
                      What do you mean exactly?
                      Can you provide us with an example of bean you added and modified place you inject it ?

                      Comment


                      • #12
                        Hi ch4mp,

                        In service-context.xml, please see the definition of quoteService and myObjectBO beans. I am trying to inject myObjectBO into quoteService bean.

                        here’s my QuoteServiceImpl class:

                        Code:
                        package com.totsp.sample.client;
                        import java.util.ArrayList;
                        import java.util.List;
                        import java.util.Random;
                        
                        import com.google.gwt.user.server.rpc.RemoteServiceServlet;
                        import com.totsp.sample.bo.IMyObjectBO;
                        
                        public class QuoteServiceImpl extends RemoteServiceServlet implements QuoteService {
                        private Random randomizer = new Random();
                        private static List quotes = new ArrayList();
                        private IMyObjectBO myObjBO = null;
                        
                        static {
                        quotes.add(”No great thing is created suddenly - Epictetus”);
                        quotes.add(”Well done is better than well said - Ben Franklin”);
                        }
                        
                        public void setMyObjBO(IMyObjectBO myObjBO) {
                        this.myObjBO = myObjBO;
                        }
                        
                        public String getQuote(){
                        return quotes.get(randomizer.nextInt(quotes.size()));
                        }
                        
                        }
                        I set a breakpoint on the setter of myObjBO and the getQuote method. On initializing the context I’m getting the breakpoint from the setter for myObjBO been invoked and I see that property been injected with correct value. But, when the getQuote method is been invoked, the myObjBO is null. So somewhere in the middle (I cannot find exactly where ) the spring bean myObjBO is been wipe out (??) and not injected anymore. Is there any process in place that keep active the beans that extends the RemoteServiceServlet while the app is running? Any ideas?

                        Thank you,
                        Cristian

                        Comment


                        • #13
                          Hi,

                          I have the same issue, using my domain classes in my client side GWT implementation.

                          my package structure is like the following:
                          com.webmailr.entity [all my domain classes]
                          com.webmailr.client [GWT client classes]
                          com.webmailr.client.service [service Interfaces]
                          com.webmailr.server [service implementations]

                          in my services I try to use classes from my entity package. I've implemented those with IsSerializable.
                          However, when using the GWT-compile script, I get the following errors:

                          Code:
                          [java]       [ERROR] Line 16: No source code is available for type com.webmailr.entity.user.User; did you forget to inherit a required module?
                          Note: I don't get this error when implementing those classes in the com.webmailr.server package.

                          The way I understand it, the compiler can't "find" the source for those files, however it's in the very same Eclipse project and 'src' folder...
                          I understand this has something to do with the client-side compiling of those classes...

                          I've been reading about this, and I think I'm missing out on something. I don't want to duplicate models as stated before. So what am I doing wrong ? :-)

                          Comment


                          • #14
                            Hi Dotbart, this one may be easy (RTFgoogleM). Java sources are required to produce client side javascript.
                            • have you declared entity package as a GWT module (Entity.gwt.xml in com.webmailr package) ?
                            • Is Entity GWT module included in your client module (<inherits name="com.webmailr.Entity"/> in YourApp.gwt.xml) ?
                            • Are sources attached to the entity jar (if any) ?
                            • Have you declared a java dependency on both entity and entity-sources jars ?
                            • If using maven, have you re-installed sources ?

                            Hi Cristian, I had no time to read and reproduce the tutorial you mentioned. Maybe tonight but really not sure.

                            Comment


                            • #15
                              Oh, thanks a lot! Silly me for diagonally reading the Google manual, and therefore skipping The Module XML part.

                              However, now I'm on track with the problem Christoph and behrooznobakht were facing.

                              I use Hibernate Annotations for my mapping. When importing my entity's using the Module XML file, GWT can't file the javax.persistence.* paths.

                              How can I handle that part? Putting all of my mapping in a hbm.xml file seems like the only 'pluggable' option (to make my domain model entirely independant from anything else). But it takes away the fun and speed of Hibernate Annotation development :-)

                              Comment

                              Working...
                              X