a gwt application with mvp pattern deploying to cloudfoundry using spring roo
DESCRIPTION
GWT, MVP, Activites&Places, Spring Roo, CloudFoundryTRANSCRIPT
GDG 2013
MVP GWT application with Spring Roo and CloudFoundry
Ali ParmaksızJan 19, 2013
http://aliparmaksiz.blogspot.com/
@parmaksiza
Agenda
• MVP Pattern (GWT)• Activites & Places (GWT)• MongoDb (NoSql)• Spring Roo (RAD for Java)• CloudFoundry (PAAS)
MVP Pattern GWT
ProxyServiceAsync proxyservice = ProxyService.Util.getInstance();
@UiField LabelElement listLabel;@UiField Anchor continueButton;@UiField Anchor backButton;@UiField SpanElement continueButtonSpan;@UiField SpanElement backButtonSpan;@UiField TextBox listName;@UiField Image listNameGif;@UiField HTMLPanel createListPanel;@UiField Validation validationMessages;
private void callServerSideValidation(final String listNameText) {new RPCCall<ServiceResponse<ResultWithError>>() { @Overrideprotected void callService(AsyncCallback<ServiceResponse<ResultWithError>> cb) {
proxyservice.createListNameIfValid(listNameText,cb);}
@Overridepublic void onFailure(Throwable caught) { System.out.println(caught);
}@Overridepublic void onSuccess(ServiceResponse<ResultWithError> result) { List<ValidationError> validationErrors = result.getResult().getErrorList(); pressErrorMessage(validationErrors);
if(validationErrors == null || validationErrors.size() == 0){infoModel.setResult(result.getResult().getServiceResult());infoModel.setListName(listNameText); PageNavigationReadyEvent event = new
PageNavigationReadyEvent(PageNavigationReadyEvent.BUTTON_DIRECTION_FORWARD, CreateListResult.class.getName()); serviceHandlerManager.fireEvent(event);
} } }.retry(0); }
GWT hears you
MVP Pattern(View)• View
public class ContactsView extends Composite implements ContactsPresenter.Display { private final Button addButton; private final Button deleteButton; private FlexTable contactsTable; private final FlexTable contentTable; public ContactsView() { DecoratorPanel contentTableDecorator = new DecoratorPanel(); initWidget(contentTableDecorator); contentTableDecorator.setWidth("100%"); contentTableDecorator.setWidth("18em"); ************************ public void setData(List<String> data) { contactsTable.removeAllRows(); for (int i = 0; i < data.size(); ++i) { contactsTable.setWidget(i, 0, new CheckBox()); contactsTable.setText(i, 1, data.get(i)); } }
MVP Pattern(Presenter)public class ContactsPresenter implements Presenter { private List<ContactDetails> contactDetails; public interface Display { HasClickHandlers getAddButton(); HasClickHandlers getDeleteButton(); HasClickHandlers getList(); void setData(List<String> data); int getClickedRow(ClickEvent event); List<Integer> getSelectedRows(); Widget asWidget(); } private final ContactsServiceAsync rpcService; private final HandlerManager eventBus; private final Display display;
MVP Pattern(Presenter) private void fetchContactDetails() { rpcService.getContactDetails(new AsyncCallback<ArrayList<ContactDetails>>() { public void onSuccess(ArrayList<ContactDetails> result) { contactDetails = result; sortContactDetails(); List<String> data = new ArrayList<String>(); for (int i = 0; i < result.size(); ++i) { data.add(contactDetails.get(i).getDisplayName()); } display.setData(data); } public void onFailure(Throwable caught) { Window.alert("Error fetching contact details"); } });
Activities & Places
• Browser History Management• Create bookmarkable URLs• Browser's back button and bookmarks to work as
users expect• MVP ? • GWT recommends this pattern as best practice
• http://www.google.com/events/io/2011/sessions/high-performance-gwt-best-practices-for-writing-smaller-faster-apps.html
Activity
• Represents something the user is doing• no Widgets or UI code• Restore state ("wake up")• Perform initialization ("set up")• Load a corresponding UI ("show up")• Call service
Activity@Overridepublic void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
HelloView helloView = clientFactory.getHelloView();helloView.setName(name);helloView.setPresenter(this);containerWidget.setWidget(helloView.asWidget());
}
/** * Ask user before stopping this activity */@Overridepublic String mayStop() {
return "Please hold on. This activity is stopping.";}
/** * Navigate to a new Place in the browser
*/public void goTo(Place place) {
clientFactory.getPlaceController().goTo(place);}
/** * Also some Service calls can made here */
Activitypublic class EditContactActivity extends AbstractActivity {
public interface IEditDisplay {HasClickHandlers getSaveButton();
HasClickHandlers getCancelButton();
HasValue<String> getFirstName();}private Contact contact;private final ContactsServiceAsync rpcService;private final EventBus eventBus;private final IEditDisplay display;private final PlaceController placeController;
public EditContactActivity(NewContactPlace place, ClientFactory clientFactory) {this.rpcService = clientFactory.getContactServiceRPC();this.eventBus = clientFactory.getEventBus();this.contact = new Contact();this.display = clientFactory.getEditContactView();this.placeController = clientFactory.getPlaceController();bind();
}
Place
• Java object representing a particular state of the UI
• A Place can be converted to and from a URL history token
• PlaceController makes back button/bookmarks work like user expect
• PlaceTokenizers map to / from String tokens on URL
Placeimport com.google.gwt.place.shared.Prefix;public class EditContactPlace extends Place {
private String placeName;public EditContactPlace(String token) {
this.placeName = token;}public String getPlaceName() {
return placeName;}@Prefix("edit")public static class Tokenizer implements PlaceTokenizer<EditContactPlace> {
@Overridepublic String getToken(EditContactPlace place) {
return place.getPlaceName();}@Overridepublic EditContactPlace getPlace(String token) {
return new EditContactPlace(token);}
}
PlaceHistoryMapper
import com.google.gwt.place.shared.PlaceHistoryMapper;import com.google.gwt.place.shared.WithTokenizers;
@WithTokenizers({NewContactPlace.Tokenizer.class, EditContactPlace.Tokenizer.class, ContactPlace.Tokenizer.class})
public interface AppPlaceHistoryMapper extends PlaceHistoryMapper { }
AppActivityMapperpublic class AppActivityMapper implements ActivityMapper {
private ClientFactory clientFactory;
public AppActivityMapper(ClientFactory clientFactory) {super();this.clientFactory = clientFactory;
}
@Overridepublic Activity getActivity(Place place) {
GWT.log("Place called: " + place);
if(place instanceof ContactPlace) {return new ContactsActivity(clientFactory);
} else if (place instanceof EditContactPlace) {return new EditContactActivity((EditContactPlace) place, clientFactory);
} else if (place instanceof NewContactPlace) {return new EditContactActivity((NewContactPlace) place, clientFactory);
}return null;
}
}
Places : go to
Places: go to
Places: back and forth
Activities & Places
To Be Honest: It’s too Hard to Get Started on the JVM
• Modern enterprise Java is way better than 5 years ago• But…it’s still too hard to… – Start a new Java project – Obtain and integrate all the necessary software• Too much of our time is spent doing things that add
too little value• We have great building blocks, but we need to improve the experience (Thanks to Rod Johnson :P )
Competitors ?
Essential Two Problem with JVM
Noone owns about that problem
It is still to hard to start a project on JVM
But result :P
Spring Roo
• Easy to use productivity tool• Code generator – Spring based enterprise applications.• Development time only.• No negative performance impact• No memory overhead
Spring Roo
• Entity support• Field management• Persistence• JUnit testing• Spring MVC controller• Spring Security• GWT• Flex• ……………………
CloudFoundry-The Industry's Open Platform as a Service
• Services - Caldecott – tunnel into your services, explore with standard client tools - PostgreSQL, RabbitMQ
• Frameworks, Runtimes, and Tools - Java and Ruby Auto-Reconfiguration - Scala, node.JS 0.6.*, Erlang, JRuby, PHP, Python, .NET, Spring 3.1, Grails 2.0 - Multi-Node Chef based deployment tools - Maven Plugin, Eclipse Integration - VMC manifests, Java Debugging, Rails Console
• Micro Cloud Foundry
Deploy An Application to CloudFoundry (1)
Deploying an Application to CloudFoundry (2)
• Installing vmc is easy once you have installed Ruby and RubyGems on your computer.
• prompt$ sudo gem install vmc (linux&mac)• prompt> gem install vmc (windows)
Steps
• prompt$ vmc target https://api.cloudfoundry.com• prompt$ vmc login• vmc passwd• vmc push• vmc apps
Hey Coding Time :P :P
• Come