gwt enterprise edition

Post on 25-May-2015

992 Views

Category:

Technology

8 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

GWT Enterprise Edition

By: Gilad Garon

March 2012

#javaedge2012

» Vanilla GWT

» Improved RPC

» Enhanced Request Factory

» Request Builder

» Tying it all together

Overview:

Agenda

VANILLA GWT SERVER SIDE

» Communication is always asynchronous

» Client side code is Java translated to JavaScript

» Server side code is based on GWT Servlets

The Lowdown on GWT RMI:

Vanilla GWT Server Side

» GWT RPC

Service oriented

» RequestFactory

Data oriented

» RequestBuilder

Manual HTTP Requests

Three Flavors of RMI:

Vanilla GWT Server Side

Vanilla GWT RMI

RemoteServiceServlet

RequestFactoryServlet

HttpServlet

GWT Application WAR

HTTP (Async)

GWT server side application:

» GWT RPC

Standalone services: Authentication

» RequestFactory

Data services: Domain entity CRUD operations

» RequestBuilder

Cross site integration: Reading data from a remote server

Use case examples:

Vanilla GWT Server Side

IMPROVED RPC

» Each service is a standalone RPC Servlet

» Client invokes a generated interface

» Transports concrete java objects

GWT-RPC in a nutshell:

Vanilla RPC

» 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

How can we improve it?

Vanilla RPC

» 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

Meet the Command Pattern:

Command Pattern

Dispatcher RPC Servlet

Architecture

Client Browser

Action

Action Result

Dispatch Service

Action Handler

Async Dispatcher

Command Pattern

Action

Result

» 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

Benefits:

Command Pattern

Command Pattern, Example

public class GetDocumentByIDAction extends Action<GetDocumentByIDResult> { private String id; public String getId() { return id; } }

Action:

public class GetDocumentByIDResult implements Result { private String documentContents; public String getDocument() { return documentContents; } }

Result:

Command Pattern

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); } }

ActionHandler:

» 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

Integrate with an IoC container:

IoC / DI

Simple Spring example:

Spring Integration

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(); } }

Guiceified Servlet:

Guice Integration

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(); } }

» Command pattern

Reduces number of RPC servlets

Allows for smart RMI

» IoC Integration

Enables single bootstrap

Allows Dependency Injection

So far we’ve seen:

Summary

Replace the entire RPC mechanism:

» GWT offers static methods to process RPC

» We can use it to create our own RPC Servlets implementations

What else can we do?

DIY RPC:

DIY RPC:

HttpServlet.doPost()

RPCServletUtils. readContentAsGwtRpc(request)

HttpServletRequest request

RPC.decodeRequest(payload,…)

String payload

Invoke Method by reflection using: • rpcRequest.getMethod() • rpcRequest.getParameters()

RPCRequest request

RPC.encodeResponseForSuccess (rpcRequest.getMethod(), result,

serializationPolicy, serializationFlags);

RPCServletUtils.writeResponse (getServletContext(), response,

payload, gzipEncode)

String payload

Object result

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

The main players:

Domain definition RequestFactory equivalent

Entity EntityProxy

POJO ValueProxy

Service definitions RequestContext

Service implementations N/A

Request Factory

Request Factory

Other players:

» Entity Locators

▪ A way to track domain entities

» Service Locators

▪ A way to instantiate domain services

@Entity public class Person { @Id private Long id; private Integer version; private String firstName private String lastName @Embedded private Address address; ... }

@ProxyFor(value=Person.class, locator=MyLocator.class) public interface PersonProxy extends EntityProxy { Long getId(); Integer getVersion(); String getFirstName(); String getLastName(); //ValueProxy AddressProxy getAddress(); ... }

Entity mappings:

JPA Entity: Entity Proxy:

Request Factory

@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); }

RequestContext:

public class PersonDAO { public void saveOrUpdate(Person person); public List<Person> findAllPersons(); public Person findPerson(Long id); }

Our actual service:

Request Factory

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… }

Entity Locator:

Request Factory

To track entities, we need an entity locator:

To instantiate the services, we need a service locator:

public class MyServiceLocator implements ServiceLocator { @Override public Object getInstance(Class<?> clazz) { try { return clazz.newInstance(); } catch ( //Damn you checked exceptions!!! ){ } } }

Request Factory

ServiceLocator:

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

Request Factory

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 ;-)

How does it work? Meet the ServiceLayerDecorator:

ServiceLayerDecorator

» Override default behaviors such as:

Instantiating locators

Instantiating service locators

Instantiating services

Domain / Proxy / Domain mapping

Domain method invocations

AOP like behavior

What can we do with it?

ServiceLayerDecorator

» Extend RequestFactoryServlet

» Create a ServiceLayerDecorator with access to your Guice injector

» Override the createServiceInstance method

Instantiate a service with Guice:

ServiceLayerDecorator

Extended RequestFactory Servlet:

ServiceLayerDecorator

public class GuiceRequestFactoryServlet extends RequestFactoryServlet { public GuiceRequestFactoryServlet() { super(new DefaultExceptionHandler(), new GuiceServiceLayerDecorator()); } }

Guicified ServiceLayerDecorator:

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); } } }

» Extend RequestFactoryServlet

» Create a ServiceLayerDecorator with access to your Spring context

» Override the createLocator method

Instantiate an entity Locator with Spring:

ServiceLayerDecorator

Extended RequestFactory Servlet:

ServiceLayerDecorator

public class SpringRequestFactoryServlet extends RequestFactoryServlet { public SpringRequestFactoryServlet() { super(new DefaultExceptionHandler(), new SpringServiceLayerDecorator()); } }

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); } } }

ServiceLayerDecorator

» Every proxy method must have a domain entity equivalent method

» Override this behavior with the ServiceLayerDecorator

Execute business method on entity proxies

Calculated Fields

Calculated Fields

@Entity public class Person { @Id private Long id; private Integer version; private String firstName private String lastName @Embedded private Address address; ... }

@ProxyFor(value=Person.class, locator=SomeLocator.class) public interface PersonProxy extends EntityProxy { Long getId(); Integer getVersion(); String getFirstName(); String getLastName(); //Doesn’t exist in domain entity String getDisplayName(); //ValueProxy AddressProxy getAddress(); ... }

JPA Entity: Entity Proxy:

Proxy modification:

Calculated Fields

@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(); ... }

SLD Modification:

Calculated Fields

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);

}

» RequestContext Inheritance

» Generify the EntityLocator

» JSR 303

What else can we do?

Enhanced Request Factory

» 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

Remove the Boilerplate:

RequestContext Inheritance

RequestContext Inheritance

public interface BasicRequestContext<T extends BaseEntityProxy> extends RequestContext { Request<Void> saveOrUpdate (BaseEntityProxy entityProxy); Request<T> find(Long id); }

@Service(value=PersonDAO.class,locator = MyServiceLocator.class) public interface PersonRequest extends BasicRequestContext<PersonProxy>{ }

Generic RequestContext:

Actual RequestContext:

One EntityLocator for all of your entities:

Generic EntityLocator

@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…

Validations? Just add water:

JSR 303

@Entity public class Person { @Id private Long id; private Integer version; @NotNull private String firstName private String lastName @Embedded private Address address; ... }

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) { } @Override public void onConstraintViolation(Set<ConstraintViolation<?>> violations) { //Handle the violations } });

Server entity: Client side invocation:

THE REQUESTBUILDER

» Generic HTTP Requests

» Transports text

» Same Origin Policy

RequestBuilder in a nutshell:

Request Builder

» Consume data from external site

» Interact with lightweight text based services

» Download files (creativity required)

What can we use if for?

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

Fetch file from Filesystem and prepare a temporary url to file

Return URL to file in HTTP Response

Parse returned url from RequestBuilder Response

Open a new window with the file URL

(GET Request) Client Side

Server Side

Request Builder

» Support easy encoding of Pojos to JSON structures

» Usable in non-GWT code

com.google.web.bindery

» Used in RequestFactory

AutoBean Framework:

Request Builder

public interface Person { String getFirstName(); void setFirstName(String firstName); String getLastName(); void setLastName(String lastName); }

AutoBean declaration:

public interface MyFactory extends AutoBeanFactory { AutoBean<Person> person(); }

AutoBean Factory declaration:

Request Builder

//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(); }

Using the Framework:

Request Builder

WIRING IT ALL TOGETHER

» 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

Required ingredients:

Guice your GWT App

public class MyContextListener extends GuiceServletContextListener{ @Override protected Injector getInjector() { return Guice.createInjector(new MyServletModule()); } }

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); } }

ContextListener:

ServletModule:

Guice your GWT App

<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 >

Web.xml:

Guice your GWT App

» Server Side:

1 x RequestFactory Servlet

1 x Dispatcher Servlet

» Web.xml:

1 x Spring Dispatcher Servlet

Required ingredients:

Spring your GWT App

<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 >

Web.xml:

Spring your GWT App

Application context:

<beans> <context:component-scan base-package="com.alphacsp.theedge "/> <mvc:annotation-driven/> </beans>

@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); } }

RequestFactory Servlet:

Spring your GWT App

RESOURCES

Resources

» Official Docs: https://developers.google.com/web-toolkit/doc/latest/tutorial/RPC

» Lifecycle (Great read): http://fascynacja.wordpress.com/2011/04/17/exciting-life-of-entity-proxies-in-contexts-of-requestfactory/

RequestFactory

Resources

» Official Docs: http://code.google.com/p/google-guice/wiki/ServletModule

GWT Guice Servlet Module

Resources

» Howto:

▪ http://krams915.blogspot.com/2012/02/spring-31-gwt-maven-plugin-and_3309.html

▪ http://crazygui.wordpress.com/2011/12/06/spring-gwt-software-architecture-for-scalable-applications-part-1/

GWT Spring Integration

THANK YOU!

top related