design pattern for common functionality between Activities

118 views
Skip to first unread message

koma

unread,
Nov 8, 2010, 6:43:38 PM11/8/10
to Google Web Toolkit
Hi GWT gurus,

Learning the new GWT 2.1 framework and I got security up&running on my
GAE application.
Now working with the new Activities/Places.

My applicaiton will have a login/logout link in the top right of the
website/app.

How do I keep this link in sync with the security status of the
current visitor/user.
Will every activity have to check for the status of the of current
user ?

Do I create a super class AbstractMyApplicationActivity that
implements this functionality and then call this in start() for each
child activity ?

like this
public AbstractMyApplicationActivity extends AbstractActivity {
public void updateLoginLogoutLink() {
// set the login/logout link correctly
}
}

public SomeActivity extends AbstractMyApplicationActivity {
public void start(AcceptsOneWidget containerWidget, EventBus
eventBus) {
updateLoginLogoutLink()
... some other activity specific stuff.
}
}

Is there a more elegant pattern for implementing this? Now the
responsibility of making this calling is present in every activity....
feels uncomfortable;

thx,

koen

Nicolas Antoniazzi

unread,
Nov 8, 2010, 7:30:56 PM11/8/10
to google-we...@googlegroups.com
I can give you what I did in my application. Maybe that you will prefer this method :

* When the application loads, the server store a login/logout status of the user in a json format (just for optimization like this : http://code.google.com/intl/fr/webtoolkit/articles/dynamic_host_page.html. You can make an init query to the server to get the status instead of the previous method, but it is a bit slower)

* My login/logout link is inside its own activity and it has its own activity manager too.
* I send a new LoginStatusEvent(boolean login) when my status is updated and it is handled by my Login/Logout activity.
* When user successfully login or logout, I send a new LoginStatusEvent.
* On server side, I use a security framework that check permission on rpc call. If user is not logged in (session has expired) but want to access to a "secured method" -> I throw a special remote exception. This exceptions is handled by a custom AsyncCallback that will redirects the user to a login page + sends a new LoginStatusEvent(false)

Tell me if this is not clear.

Nicolas.

2010/11/9 koma <ko...@koma.be>

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.


koma

unread,
Nov 12, 2010, 10:08:55 AM11/12/10
to Google Web Toolkit
I think i start to understand, after reading the blog posts from
Thomas Broyer here: http://tbroyer.posterous.com/gwt-21-activities-nesting-yagni
and the other posts in this series

Looking at a host page, you can identify different display areas.
Every "dynamic" area - not the static part of the host page - is
managed by an activity manager, which decides the activity to live in
the display area.
The applications switches between places and changing places triggers
each activity manager to update its part of the display area;

So I think I have to create a
- menu activity manager
- main content activity manager
- login/logout link activity manager
- sidebar activity manager.


What do think ? Is my understanding of the "big picture" correct ?

koma

unread,
Nov 17, 2010, 6:31:02 AM11/17/10
to Google Web Toolkit
hi Nicolas & others,

I understand how you work with the dynamic hosted page, but how do you
throw the remote exception like you describe here :

On server side, I use a security framework that check permission on
rpc
call. If user is not logged in (session has expired) but want to
access to a
"secured method" -> I throw a special remote exception. This
exceptions is
handled by a custom AsyncCallback that will redirects the user to a
login
page + sends a new LoginStatusEvent(false)

I am using Requestfactory and I have "/gwtRequest" behind a security
constraint; so I can block unauthorized request, but I am not
receiving a RemoteException; Neither is 'onViolation' or 'onFailure'
triggered; My console displays just a JSON exception that occurs.

thx

Koen


Nicolas Antoniazzi

unread,
Nov 18, 2010, 2:38:59 PM11/18/10
to google-we...@googlegroups.com, ko...@koma.be
Hello Koen,

I never used Requestfactory so I do not know if it is similar to RPC. In my case, all my RPC Services can send a ServiceRemoteException (declared in Services interfaces). (ServiceRemoteException is a custom exception that I extended for my needs)

@RemoteServiceRelativePath("GWT.rpc")
public interface MyRemoteService extends RemoteService {
  public void myRemoteMethod() throws ServiceRemoteException;
}

When There is a security exception (I am using a framework to manage security checks called Shiro. http://shiro.apache.org/. I plugged it over Guice and its AOP mechanism. Like this I can use special annotation on my methods like @RequireAuthentication, @RequiresRole("role"), @RequiresGuest, ... and every time that a user try to access a method without the correct permissions, a shiro exception is thrown.)

All Security Exception are caught by a global server exception catcher. (I extendend the method processCall of the RemoteServiceServlet class for this).
When a Shiro Security Exception is caught, I create a new RemoteServiceException with some extra parameters that contains the security exception type for the client.

Now, on the client, with RPC call, you calls methods with something similar to this :

myService.myRemoteMethod(new AsyncCallback<Void>() {
  @override
  public void onSuccess(Void v) {
  }

  @override
  public void onFailure(Throwable t) {
  }
}

When a security exception occurs, the client code will execute the onFailure method. Here you can manage how to handle your exception

onFailure(Throwable t) {
  if(t instanceof RemoteServiceException) {
    ExceptionType type = ((RemoteServiceException) t).getType();
    if(type == SECURITY_AUTHENTICATION) {
      placeController.goTo(new LoginPlace());
    }
  }
}

Now, maybe that you do not want to write this code in every onFailure(), so, you can extends AsyncCallback class.

public abstract class ManagedAsyncCallback<T> extends AsyncCallback<T> {
  @override
  public void onFailure(Throwable t) {
    // .. write your common security exception management here
  }
}

then, when calling a service, you only have to override the onSuccess() in quite every case, except in special situations.

myService.myRemoteMethod(new ManagedAsyncCallback<Void>() {
  @override
  public void onSuccess(Void v) {
  }
}

I hope that it can help you :)
I do not know if RequestFactory is using somethig similar (onSuccess, onFailure).

Thanks.

2010/11/17 koma <ko...@koma.be>


--

tastic

unread,
Nov 19, 2010, 1:03:55 AM11/19/10
to Google Web Toolkit
I have been reading Thomas Broyer's blog now for a full day and am
still having an issue with loading my application. Attached it the
EntryPoint. If you can tell me what I might be doing wrong that would
be awesome.

public class Library implements EntryPoint {
Logger logger = Logger.getLogger("LibraryLogger");

private Place defaultPlace = new HomePlace("Welcome");

private LayoutPanel layoutPanel = new LayoutPanel();

private SimplePanel headerPanel = new SimplePanel();
AcceptsOneWidget headerDisplay = new AcceptsOneWidget() {
public void setWidget(IsWidget w) {
Widget widget = Widget.asWidgetOrNull(w);
layoutPanel.setWidgetVisible(headerPanel, widget != null);
headerPanel.setWidget(widget);
}
};
private SimplePanel mainPanel = new SimplePanel();
AcceptsOneWidget mainDisplay = new AcceptsOneWidget() {
public void setWidget(IsWidget w) {
Widget widget = Widget.asWidgetOrNull(w);
layoutPanel.setWidgetVisible(mainPanel, widget != null);
mainPanel.setWidget(widget);
}
};
private SimplePanel sidePanel = new SimplePanel();
AcceptsOneWidget sideDisplay = new AcceptsOneWidget() {
public void setWidget(IsWidget w) {
Widget widget = Widget.asWidgetOrNull(w);
layoutPanel.setWidgetVisible(sidePanel, widget != null);
sidePanel.setWidget(widget);
}
};
private SimplePanel footerPanel = new SimplePanel();
AcceptsOneWidget footerDisplay = new AcceptsOneWidget() {
public void setWidget(IsWidget w) {
Widget widget = Widget.asWidgetOrNull(w);
layoutPanel.setWidgetVisible(footerPanel, widget != null);
footerPanel.setWidget(widget);
}
};


/**
* This is the entry point method.
*/
public void onModuleLoad() {
// Create ClientFactory using deferred binding so we can replace
with different
// impls in gwt.xml
ClientFactory clientFactory = GWT.create(ClientFactory.class);
EventBus eventBus = clientFactory.getEventBus();
PlaceController placeController =
clientFactory.getPlaceController();

// Start ActivityManager for the main widget with our ActivityMapper
ActivityMapper headerActivityMapper = new
HeaderActivityMapper(clientFactory);
ActivityManager headerActivityManager = new
ActivityManager(headerActivityMapper, eventBus);
headerActivityManager.setDisplay(headerDisplay);

ActivityMapper sideActivityMapper = new
SideActivityMapper(clientFactory);
ActivityManager sideActivityManager = new
ActivityManager(sideActivityMapper, eventBus);
sideActivityManager.setDisplay(sideDisplay);

ActivityMapper footerActivityMapper = new
FooterActivityMapper(clientFactory);
ActivityManager footerActivityManager = new
ActivityManager(footerActivityMapper, eventBus);
footerActivityManager.setDisplay(footerDisplay);

ActivityMapper mainActivityMapper = new
MainActivityMapper(clientFactory);
ActivityManager mainActivityManager = new
ActivityManager(mainActivityMapper, eventBus);
mainActivityManager.setDisplay(mainDisplay);

// Start PlaceHistoryHandler with our PlaceHistoryMapper
AppPlaceHistoryMapper historyMapper=
GWT.create(AppPlaceHistoryMapper.class);
PlaceHistoryHandler historyHandler = new
PlaceHistoryHandler(historyMapper);
historyHandler.register(placeController, eventBus, defaultPlace);

logger.info("Layout Panel "+layoutPanel);

RootPanel.get().add(layoutPanel);
// Goes to place represented on URL or default place
historyHandler.handleCurrentHistory();

Thomas Broyer

unread,
Nov 19, 2010, 9:26:40 AM11/19/10
to Google Web Toolkit


On 19 nov, 07:03, tastic <blaketast...@gmail.com> wrote:
> I have been reading Thomas Broyer's blog now for a full day and am
> still having an issue with loading my application. Attached it the
> EntryPoint. If you can tell me what I might be doing wrong that would
> be awesome.

No where you add the different SimplePanel instances to your
LayoutPanel.

tastic

unread,
Nov 19, 2010, 12:54:46 PM11/19/10
to Google Web Toolkit
Is each display region the entire group of things, or are we saying
that a display region is something like the header of the page with a
menu or the footer of the page with links? If each display region is
the entire group, then I understand the concept of going to a new
place for each, which ultimately dictates the view to show. However,
if each display region is an individual component on the page, using
an activity mapper does not make sense. Please advise. Thank you.

koma

unread,
Nov 19, 2010, 2:05:52 PM11/19/10
to Google Web Toolkit
How I understand things, a display region is a dynamic part of a
webpage;

Depending on the place you're at, a display region is populated with a
specific activity.
A activity manager is the manager of a display region and decides the
right activity to show up for a given display region when a certain
page is showing.

So, in terms of your question : a display region can be a dynamic
menu, a sidebar, a logout/login link.... not the entire group.
An example

page with menu displayregion, maincontent displayregion, sidebar
displayregion

example page #ContactDetailsPage:FooBar
+> sidebar display region will be instructed by the sidebar-
activitymanager to start the activity GrandChildrenActivity (display
grandchildren in side bar)
+> maincontact display region will be instructed by the
maincontentarea-activitymanager to start the activity
ContactDetailsActivity (display contact details in main content area)
+> menu display region will be instructed by the menu-activitymanager
to start the activity MenuActivity (show the menu)

example page #Login
+> sidebar display region will be instructed by the sidebar-
activitymanager to display nothing (NULL)
+> maincontact display region will be instructed by the
maincontentarea-activitymanager to start the activity LoginActivity
(display login page)
+> menu display region will be instructed by the menu-activitymanager
to start the activity WelcomeActivity (show a welcome msg)

etc etc.

So far my understanding.

Koen

Marcin Misiewicz

unread,
Nov 19, 2010, 5:30:49 PM11/19/10
to Google Web Toolkit
And you are definitely right.

tastic

unread,
Nov 22, 2010, 2:05:10 PM11/22/10
to Google Web Toolkit
does anyone have a working example of say, the HelloMVP with
activities managing different display regions

koma

unread,
Nov 22, 2010, 2:11:56 PM11/22/10
to Google Web Toolkit
Not really, but it is not that hard to modify HelloMVP to make it
work.

Actually HelloMVP is a really confusing example, because

- the activities are called HelloActivity and GoodbyeActivity
- the places are called HelloPlace and GoodbyePlace

but the activities and places are orthogonal to each other. That
doesn't help to get a clearer understanding.

tastic

unread,
Nov 22, 2010, 4:41:52 PM11/22/10
to Google Web Toolkit
I think that is my entire problem. If I create an AppActivity, I am
also creating an AppPlace and trying to tie the two together. Is the
relationship between Activity and Place a one to one?

koma

unread,
Nov 22, 2010, 5:45:06 PM11/22/10
to Google Web Toolkit
No, places and activities are orthogonal to each other

a webpage consists of many display regions
every display region is managed by a activity manager

when a place change occurs, the activity managers are notified and
they decide the activity to live inside the display region

I tried to explain this in more elaborate earlier in this thread, but
here's where i got my insights from : http://tbroyer.posterous.com/gwt-21-activities

good luck,
K.

Reply all
Reply to author
Forward
0 new messages