GWT Enterprise Edition
Upcoming SlideShare
Loading in...5
×
 

GWT Enterprise Edition

on

  • 977 views

GWT brings a lot to the table on the client side: the comprehensive browser compatibility and the ease of writing in java are just a few examples to name. But, when looking at the server side, GWT can ...

GWT brings a lot to the table on the client side: the comprehensive browser compatibility and the ease of writing in java are just a few examples to name. But, when looking at the server side, GWT can be a bit lacking with the technologies it uses. Learn how to build powerful end to end Enterprise applications with GWT as your frontend and how to back it up with your favorite arsenal of tools, including, Spring, Guice and Hibernate

Statistics

Views

Total Views
977
Views on SlideShare
975
Embed Views
2

Actions

Likes
1
Downloads
14
Comments
1

1 Embed 2

http://www.linkedin.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

GWT Enterprise Edition GWT Enterprise Edition Presentation Transcript

  • #javaedge2012 GWT Enterprise Edition By: Gilad Garon March 2012
  • Agenda Overview: » Vanilla GWT » Improved RPC » Enhanced Request Factory » Request Builder » Tying it all together
  • VANILLA GWT SERVER SIDE
  • Vanilla GWT Server Side The Lowdown on GWT RMI: » Communication is always asynchronous » Client side code is Java translated to JavaScript » Server side code is based on GWT Servlets
  • Vanilla GWT Server Side Three Flavors of RMI: » GWT RPC » »  Service oriented RequestFactory  Data oriented RequestBuilder  Manual HTTP Requests
  • Vanilla GWT RMI GWT server side application: RemoteServiceServlet RequestFactoryServlet HttpServlet GWT Application WAR HTTP (Async)
  • Vanilla GWT Server Side Use case examples: » GWT RPC » »  Standalone services: Authentication RequestFactory  Data services: Domain entity CRUD operations RequestBuilder  Cross site integration: Reading data from a remote server
  • IMPROVED RPC
  • Vanilla RPC GWT-RPC in a nutshell: » Each service is a standalone RPC Servlet » Client invokes a generated interface » Transports concrete java objects
  • Vanilla RPC How can we improve it? » Use the command pattern  Use a single RPC Servlet for all of your services » Integrate with an IoC container  Wire all of your services easily » Don’t use interfaces, use only concrete classes
  • Command Pattern Meet the Command Pattern: » A Single RPC Servlet for all of your services » Action class represents the client request » Result class represents the server response » ActionHandler class handles the Action and returns the Result
  • Command Pattern Architecture Dispatcher RPC Servlet Client Browser Action Handler Action Dispatch Service Action Result Async Dispatcher Action Result
  • Command Pattern Benefits: » Server side:  Single RPC Servlet for all services » Client side:     Caching Batching Centralized failure handling Undo / Redo support Don’t reinvent the wheel, use existing frameworks:  GWTP  GWT-Dispatch
  • Command Pattern, Example Action: public class GetDocumentByIDAction extends Action<GetDocumentByIDResult> { private String id; public String getId() { return id; } } Result: public class GetDocumentByIDResult implements Result { private String documentContents; public String getDocument() { return documentContents; } }
  • Command Pattern ActionHandler: public class GetDocummentByIDActionHandler implements ActionHandler<GetDocummentByIDAction, GetDocummentByIDResult> { DocumentService documentService; @Override public GetDocummentByIDResult execute(GetDocummentByIDAction action) { String doc = documentService.getDocumentById(action.getId()); return new GetDocummentByIDResult (doc); } }
  • IoC / DI Integrate with an IoC container: » Central point for configuration: » »  Services  DAO Minimizes the amount of code in your application  Inject what you need Make your application more testable  Easy way to create mockup objects
  • Spring Integration Simple Spring example: public class MyRPCServiceImpl extends RemoteServiceServlet implements MyRPCService { private ApplicationContext applicationContext; @Override public void init() { super.init() ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext (getServletContext()); } @Override public String doSomething() { return applicationContext.getBean(SpringRPCService.class).doSomething(); } }
  • Guice Integration Guiceified Servlet: public class MyRPCImpl extends RemoteServiceServlet implements MyRPC { private final SomeService service; public MyRPCImpl(){ this.service = MyGuiceFactory.getInjector().getInstance(SomeService.class); } @Override public String doSomething() { return service.doSomething(); } }
  • Summary So far we’ve seen: » Command pattern  Reduces number of RPC servlets  Allows for smart RMI » IoC Integration  Enables single bootstrap  Allows Dependency Injection
  • DIY RPC: What else can we do? Replace the entire RPC mechanism: » GWT offers static methods to process RPC » We can use it to create our own RPC Servlets implementations
  • DIY RPC: HttpServlet.doPost() HttpServletRequest request RPCServletUtils. readContentAsGwtRpc(request) String payload Invoke Method by reflection using: • • rpcRequest.getMethod() rpcRequest.getParameters() RPCRequest request RPC.decodeRequest(p ayload,…) Object result RPC.encodeResponseForSuccess (rpcRequest.getMethod(), result, serializationPolicy, serializationFlags); String payload RPCServletUtils.writeResponse (getServletContext(), response, payload, gzipEncode)
  • IMPROVED REQUEST FACTORY
  • Request Factory RequestFactory in a nutshell: » Designed for Data oriented services » Lightweight » Integrates with any ORM framework
  • Request Factory Created for data oriented services: » Uses proxies as Data Transfer objects » Uses JSON as a transport layer » Transfers shallow object graph » Tracks your domain objects, transfers only delta changes » Loosely coupled with your sever side
  • Request Factory The main players: Domain definition RequestFactory equivalent Entity EntityProxy POJO ValueProxy Service definitions RequestContext Service implementations N/A
  • Request Factory Other players: » Entity Locators ▪ A way to track domain entities » Service Locators ▪ A way to instantiate domain services
  • Request Factory Entity mappings: JPA Entity: Entity Proxy: @Entity public class Person { @Id private Long id; private Integer version; private String firstName private String lastName @ProxyFor(value=Person.class, locator=MyLocator.class) public interface PersonProxy extends EntityProxy { Long getId(); Integer getVersion(); String getFirstName(); String getLastName(); @Embedded private Address address; ... } //ValueProxy AddressProxy getAddress(); ... }
  • Request Factory RequestContext: @Service(value=PersonDAO.class,locator = MyServiceLocator.class) public interface PersonRequest extends RequestContext { Request<Void> saveOrUpdate(PersonProxy person); Request<List<PersonProxy>> findAllPersons(); Request<PersonProxy> findPerson(Long id); } Our actual service: public class PersonDAO { public void saveOrUpdate(Person person); public List<Person> findAllPersons(); public Person findPerson(Long id); }
  • Request Factory To track entities, we need an entity locator: Entity Locator: public class PersonLocator extends Locator<Person,Long> { @Override public Person create(Class<? extends Person> clazz) { return new Person(); } @Override public Person find(Class<? extends Person> clazz, Long id) { return PersonDAO.find(id); } //more abstract methods to override… }
  • Request Factory To instantiate the services, we need a service locator: ServiceLocator: public class MyServiceLocator implements ServiceLocator { @Override public Object getInstance(Class<?> clazz) { try { return clazz.newInstance(); } catch ( //Damn you checked exceptions!!! ){ } } }
  • Request Factory Summary: » Entities  Your JPA/JPO entities » Entity Proxy  RequestFactory equivalents for your entities » Value Proxy  RequestFactory equivalents for your pojos » Request Context  Interfaces declaring your exposed services » Entity Locators  An API that allows RequestFactroy to interact with the domain world » Service Locators  An API that allows RequestFactroy to instantiate your servcies
  • ServiceLayerDecorator How does it work? Meet the ServiceLayerDecorator: A Chain of decorators:  Determines how RF interacts with the Domain world  Creates objects  Handles domain / proxy / domain mappings  Handles method invocations We can override it ;-)
  • ServiceLayerDecorator What can we do with it? » Override default behaviors such as:  Instantiating locators  Instantiating service locators  Instantiating services  Domain / Proxy / Domain mapping  Domain method invocations  AOP like behavior
  • ServiceLayerDecorator Instantiate a service with Guice: » Extend RequestFactoryServlet » Create a ServiceLayerDecorator with access to your Guice injector » Override the createServiceInstance method
  • ServiceLayerDecorator Extended RequestFactory Servlet: public class GuiceRequestFactoryServlet extends RequestFactoryServlet { public GuiceRequestFactoryServlet() { super(new DefaultExceptionHandler(), new GuiceServiceLayerDecorator()); } }
  • ServiceLayerDecorator Guicified ServiceLayerDecorator: public class GuiceServiceLayerDecorator extends ServiceLayerDecorator { private Injector injector = MyGuiceFactory.getInjector(); @Override public Object createServiceInstance (Class<? extends RequestContext> clazz) { Class<?> serviceClass = getTop().resolveServiceClass(clazz); try { return injector.getInstance(clazz); } catch (RuntimeException e) { return super.createServiceInstance(requestContext); } } }
  • ServiceLayerDecorator Instantiate an entity Locator with Spring: » Extend RequestFactoryServlet » Create a ServiceLayerDecorator with access to your Spring context » Override the createLocator method
  • ServiceLayerDecorator Extended RequestFactory Servlet: public class SpringRequestFactoryServlet extends RequestFactoryServlet { public SpringRequestFactoryServlet() { super(new DefaultExceptionHandler(), new SpringServiceLayerDecorator()); } }
  • ServiceLayerDecorator Springified ServiceLayerDecorator: public class SpringServiceLayerDecorator extends ServiceLayerDecorator private final ApplicationContext applicationContext; public SpringServiceLayerDecorator(){ this.applicationContext = WebApplicationContextUtils.getWebApplicationContext( SpringRequestFactoryServlet.getThreadLocalServletContext()); } @Override public <T extends Locator<?, ?>> T createLocator(Class<T> clazz) { try { return applicationContext.getBean(clazz); } catch (BeansException e) { return super.createLocator(clazz); } } }
  • Calculated Fields Execute business method on entity proxies » Every proxy method must have a domain entity equivalent method » Override this behavior with the ServiceLayerDecorator
  • Calculated Fields JPA Entity: Entity Proxy: @Entity public class Person { @ProxyFor(value=Person.class, locator=SomeLocator.class) public interface PersonProxy extends EntityProxy { @Id private Long id; private Integer version; private String firstName private String lastName @Embedded private Address address; ... Long getId(); Integer getVersion(); String getFirstName(); String getLastName(); //Doesn’t exist in domain entity String getDisplayName(); //ValueProxy AddressProxy getAddress(); ... } }
  • Calculated Fields Proxy modification: @SkipInterfaceValidation @ProxyFor(value=Person.class, locator=SomeLocator.class) public interface PersonProxy extends BaseEntityProxy { Long getId(); Integer getVersion(); String getFirstName(); String getLastName(); @CalculatedField(SomeOtherSerivce.class) String getDisplayName(); //ValueProxy AddressProxy getAddress(); ... }
  • Calculated Fields SLD Modification: public class MyServiceLayerDecorator extends ServiceLayerDecorator{ //code is simplified due to size limits… @Override public Object getProperty(Object domainObject, String property) { try { return super.getProperty(domainObject, property); } catch (Throwable t) { Class<? extends BaseEntityProxy> clientClass = super.resolveClientType(domainObject.getClass(), BaseEntityProxy.class, false); Method proxyMethod = clientClass.getDeclaredMethod(methodName); CalculatedField annotation = proxyMethod.getAnnotation(CalculatedField.class); Class<?> value = annotation.value(); Method domainMethod = value.getDeclaredMethod(methodName,domainObject.getClass()); domainMethod.setAccessible(true); return domainMethod.invoke(injector.getInstance(value), domainObject); }
  • Enhanced Request Factory What else can we do? » RequestContext Inheritance » Generify the EntityLocator » JSR 303
  • RequestContext Inheritance Remove the Boilerplate: » You can inherit a RequestContext » You can use Generics, but with limitations:  Method parameter cannot be generic, casting is required  Method return type can be generic
  • RequestContext Inheritance Generic RequestContext: public interface BasicRequestContext<T extends BaseEntityProxy> extends RequestContext { Request<Void> saveOrUpdate (BaseEntityProxy entityProxy); Request<T> find(Long id); } Actual RequestContext: @Service(value=PersonDAO.class,locator = MyServiceLocator.class) public interface PersonRequest extends BasicRequestContext<PersonProxy>{ }
  • Generic EntityLocator One EntityLocator for all of your entities: @Component public class BaseEntityLocator extends Locator<BaseEntity, Long> { @Autowired private BaseDAO baseDAO; @Override public BaseEntity create(Class<? extends BaseEntity > clazz) { return clazz.newInstance(); } @Override public BaseEntity find(Class<? extends BaseEntity > clazz, Long id) { return (BaseEntity) baseDAO.find(aLong, aClass); } //more abstract methods to override…
  • JSR 303 Validations? Just add water: Server entity: Client side invocation: @Entity public class Person { @Id private Long id; private Integer version; PersonProxy person = personRequest.create(PersonProxy.class); someEntityProxy.setfName(null); someEntityProxy.setlName("Garon"); someRequest.save(someEntityProxy).fire(new Receiver<Void>() { @Override public void onSuccess(Void response) { } @NotNull private String firstName private String lastName @Override public void onConstraintViolation(Set<ConstraintViolation<?>> violations) { //Handle the violations } @Embedded private Address address; ... } });
  • THE REQUESTBUILDER
  • Request Builder RequestBuilder in a nutshell: » Generic HTTP Requests » Transports text » Same Origin Policy
  • Request Builder What can we use if for? » Consume data from external site » Interact with lightweight text based services » Download files (creativity required)
  • Request Builder Simple service example: public void executeQuery(String url, AsyncCallback<String>callback){ String url = “http://javaedge.com/ws/getSpeakersList/json” RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url); builder.sendRequest(null, new RequestCallback() { public void onResponseReceived(Request request, Response response) { String response = response.getText() callback.onSuccess(response); } }); }
  • Request Builder File download flow example: Send Http GET Request Using RequestBuilder Return URL to file in HTTP Response Open a new window with the file URL (GET Request) Fetch file from Filesystem and prepare a temporary url to file Parse returned url from RequestBuilder Response Client Side Server Side
  • Request Builder AutoBean Framework: » Support easy encoding of Pojos to JSON structures » Usable in non-GWT code  com.google.web.bindery » Used in RequestFactory
  • Request Builder AutoBean declaration: public interface Person { String getFirstName(); void setFirstName(String firstName); String getLastName(); void setLastName(String lastName); } AutoBean Factory declaration: public interface MyFactory extends AutoBeanFactory { AutoBean<Person> person(); }
  • Request Builder Using the Framework: //Creating an AutoBean public Person createPerson(){ MyFactory factory = GWT.create(MyFactory.class); AutoBean<Person> person = factory.person(); return person.as(); } //Serializing a bean to JSON String serializeToJson(Person person) { AutoBean<Person> bean = AutoBeanUtils.getAutoBean(person); return AutoBeanCodex.encode(bean).getPayload(); } // Deserializing a bean from JSON Person deserializeFromJson(String json) { AutoBean<Person> bean = AutoBeanCodex.decode(factory, Person.class, json); return bean.as(); }
  • WIRING IT ALL TOGETHER
  • Guice your GWT App Required ingredients: » Server Side: »  1 x Guice Servlet Context Listener  1 x Guice Servlet Module  1 x RequestFactory Servlet  1 x Dispatcher Servlet Web.xml:  1 x Guice Filter
  • Guice your GWT App ContextListener: public class MyContextListener extends GuiceServletContextListener{ @Override protected Injector getInjector() { return Guice.createInjector(new MyServletModule()); } } ServletModule: public class MyServletModule extends ServletModule { @Override protected void configureServlets() { serve(“rf_url”).with(MyRequestFactoryServlet.class); serve(“rpc_ul”).with(MyDisptacherSerlet.class); Multibinder<ServiceLayerDecorator> binder = Multibinder.newSetBinder(binder(), ServiceLayerDecorator.class); binder.addBinding().to(MyServiceLayerDecorator.class); } }
  • Guice your GWT App Web.xml: <web-app> <filter> <filter-name>guiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>guiceFilter</filter-name> <url-pattern>/*</ url-pattern > </filter-class> <listener> <listener-class>com.alphacsp.theedge.server.MyContextListener</listener-class> </filter-class> … </ web-app >
  • Spring your GWT App Required ingredients: » Server Side: »  1 x RequestFactory Servlet  1 x Dispatcher Servlet Web.xml:  1 x Spring Dispatcher Servlet
  • Spring your GWT App Web.xml: <web-app> <servlet> <servlet-name>SpringGWT</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringGWT</servlet-name> <url-pattern>your_url_mapping</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </filter-class> … </ web-app >
  • Spring your GWT App Application context: <beans> <context:component-scan base-package="com.alphacsp.theedge "/> <mvc:annotation-driven/> </beans> RequestFactory Servlet: @Controller public class SpringRequestFactoryServlet extends RequestFactoryServlet { @Autowired public SpringRequestFactoryServlet (ServiceLayerDecorator... serviceDecorators){ super(new DefaultExceptionHandler(), serviceDecorators); } @Override @RequestMapping("/rf") protected void doPost(HttpServletRequest request, HttpServletResponse response){ super.doPost(request, response); } }
  • RESOURCES
  • Resources GWT RPC » Official Docs : https://developers.google.com/webtoolkit/doc/latest/tutorial/RPC » Command Pattern: ▪ http://www.google.com/events/io/2009/sessions/Go ogleWebToolkitBestPractices.html (YouTube) ▪ http://code.google.com/p/gwtplatform/wiki/GettingStartedDispatch ▪ http://code.google.com/p/gwt-dispatch/
  • Resources RequestFactory » Official Docs: https://developers.google.com/webtoolkit/doc/latest/tutorial/RPC » Lifecycle (Great read): http://fascynacja.wordpress.com/2011/04/17 /exciting-life-of-entity-proxies-in-contexts-ofrequestfactory/
  • Resources GWT Guice Servlet Module » Official Docs: http://code.google.com/p/googleguice/wiki/ServletModule
  • Resources GWT Spring Integration » Howto: ▪ http://krams915.blogspot.com/2012/02/spring31-gwt-maven-plugin-and_3309.html ▪ http://crazygui.wordpress.com/2011/12/06/sprin g-gwt-software-architecture-for-scalableapplications-part-1/
  • THANK YOU!