View Full Version : Structure and Concept
Michi_de
23 Oct 2008, 5:47 AM
Hi!
I wanted to discuss - and what is more important - and get ideas on how to structure an gwt project?
So far i have coded only a little project with a form and a grid. Both using RPC calls to get / send data to a database.
Its workin pretty good, but im not all satisfied, :D
The projects file structure actually looks like this:
- application.html
- somestuff.css
- web.xml / xyz.gwt.xml
-- client package:
-- app.java
-- rpcservice.java
-- rpcserviceAsync.java
-- server package:
-- connector.java
-- querydb.java
-- rpcserviceImpl.java
What looks "good" so far. But when i open the "app.java" my mind explodes. Such a trivial project and 350 lines of code? With lots of methods and its realy complex to keep track of what is doing what actually.
If i wanted to start a way bigger project now how should i get the structure and concept and stuff? How do you guys startin a big project and how you structure your app.java file, so its an all clear file?
gslender
24 Oct 2008, 4:09 AM
create more classes and more packages
there is no reason why you must keep everything in the same app.class nor just in the client package .. eg...
client.App
client.login.LoginForm
client.login.RegisterForm
client.sales.NewSalesForm
client.sales.EditSalesForm
etc...
Michi_de
24 Oct 2008, 4:27 AM
Well, as i never realy learned how to do such a structure, i realy dont know how to implemnt many classes. How they should communicate to each other? For example my app.java class is this kind of spaghetti:
first the onModuleLoad() gets started:
- instantiate all the widgets i will need, do some layout stuff, get some buttons wired to listeners
- start the render(kind) method
then the render(kind) fullfills the work in designin the page:
- whether, what value kind is, it fills the panels with widgets
- for example: if it generate the statistics, it will load the method statistics()
statistics ():
- fill the right panel with statistics
- do .layout() on this panel
voila, the statistics are on the page now.
But its so bad structure.. every method is just jumping around and call others.. action listeners just all look like this:
button.addListener(Events.CellClick, new SelectionListener<ComponentEvent>() {
publicvoid componentSelected(ComponentEvent be) {
doSomethingCool();
}
});
waaaah
i realy need to learn the basics of structure an application :((
;)
gslender
24 Oct 2008, 4:32 AM
have a look at the mail example and follow this MVC design model
Michi_de
26 Oct 2008, 11:49 PM
Well, its not easy to get by, reading just the java code. Is there an more easy way, to learn something about this MVC using GWT?
MVC is easy to understand, when reading the article on wikipedia. But how exactly transfer this on GWT? Is there somewhere a tutorial or an example with explanation?
timefortea
27 Oct 2008, 1:33 AM
I too am trying to understand how to structure a large application. I have used the MVC pattern before (a little) for a JSP-based application but I am finding it a bit harder to work out how to use it for a GXT app. I have read through the Mail example and I can understand what it is doing - I even made some changes to my own example app, to use a few events. I'm not completely clear though on how this makes the design any better than not using MVC - for example registering for events is done by each controller, so you need to look at each one to work out what it is listening for, which still seems hard to follow.
I guess that fundamentally this is probably down to me not having used MVC much so I'd like to find out more about how it improves my GXT application. Having just one example and no documentation other than the API shows only how to use it - but even then I found some documentation missing ie. Controller.initialize() is not in the JavaDocs but is an override in the example.
It will all become clearer the more I play about with it but I work in a commercial environment and need to quickly understand how to effectively use this technology. Is this an unreasonable complaint?
Michi_de
27 Oct 2008, 2:13 AM
What i realy would appreciate is a guide on MVC and how to translate this to gwt with a few examples... maybe someone can take the time and write down something? Nothing too great... just the basics with some hints how to transcribe this to gwt. :-?
posta07
27 Oct 2008, 6:03 AM
Well, the same MVC principles you read on Wikipedia apply.
The GXT framework's MVC implementation follows the same rules... it's an request-driven (event-driven) MVC framework
...and instead of driven by an HTTP request like in other web-based MVC frameworks (like struts, spring, etc) the GXT's framework is driven by application events (see com.extjs.gxt.ui.client.mvc.AppEvent).
First you need to register controllers with the dispatcher.
From the explorer demo...
dispatcher = Dispatcher.get();
dispatcher.addController(new AppController());
dispatcher.addController(new NavigationController());
dispatcher.addController(new ContentController());When an event is fired by the dispatcher (see com.extjs.gxt.ui.client.mvc.Dispatcher), each one of the controllers are consulted to determine whether or not they can handle the event. (if the controller is not initialized, the initialize() method will be invoked). If a particular controller can handle the event, the controller's "handleEvent" method will be invoked.
Dispatcher Firing an event (from the explorer demo ):
dispatcher.dispatch(AppEvents.Init);
Dispatcher consulting controllers and initializing a controller if it's not initialized already:
(from com.extjs.gxt.ui.client.mvc.Dispatcher.java)
for (Controller controller : controllers) {
if (controller.canHandle(event)) {
if (!controller.initialized) {
controller.initialized = true;
controller.initialize();
}
controller.handleEvent(event);
}
}
You can see above that the dispatcher tells the controller to handle the event if the controller is capable of handling such events.
Once the controller's handleEvent method has been called, it's up the controller to determine what processing needs to occur, and which view should displaying the results.
In the case of the Explorer demo, the controller/views are trivial.... but following the same principles from any MVC discussion, the controller will be responsible for processing data (models) and the views should update.
I hope this is enough to help get an understanding... I purposefully wrote it to elicit questions and comments... feel free..
cheers
Michi_de
27 Oct 2008, 7:29 AM
Thanks posta!
Well its not easy, to learn all this stuff by just watchin code. Im gettin through more and more... but still its not easy.
Here is some MVC + GWT tutorial i found,
http://robvanmaris.jteam.nl/2008/03/09/test-driven-development-for-gwt-ui-code/
but its not explicit for Ext GWT and its using JUnit and EasyMock. But it gives a little introduction into this topic.
However im still not satisfied:
are there realy no more topics about this?
I have to learn GWT, Ext GWT, MVC just like that. My only knowledge is Java, and the last time i wrote a java application is long ago...
I need more input on the View Part now:
what does this method
forwardToView(appView, event);
do?
posta07
27 Oct 2008, 8:17 AM
Well, just like with any new technology, you'll need to stay patient and try and learn as much as possible. Becoming comfortable with the GXT MVC implementation might take some time, through trial and error, and by writing a few sample projects. If you stay persistent, it will eventually click and you will understand it.
the "forwardToView" method allows you to forward the event to a specific view for additional processing. In other words, a controller might have more than one view, and you can determine which view should handle further processing of the request.
You'll notice that the forwardToView method will ask the view to "handle" the event by calling its "handleEvent" method.
See from com.extjs.gxt.ui.client.mvc.Controller.java:
public static void forwardToView(View view, AppEvent event) {
if (!view.initialized) {
view.initialize();
view.initialized = true;
}
view.handleEvent(event);
}
If the view isn't initialized already, the initialize() method is invoked.
From within the view.handleEvent() method, you can update your widgets (depending on the request type).
For both the Controller and the View subclasses, in your "handleEvent" method you can perform logic (switch statements) to determine what gets executed for the even type.
For example in the controller's handleEvent method...
public void handleEvent(AppEvent event) {
switch (event.type) {
case AppEvents.Init:
onInit(event);
case AppEvents.HidePage:
onHidePage(event);
break;
}
}
Again... feel free to ask any other questions... I realize I wasn't extremely specific (with concrete examples), but just let me know what you need clarified.
Michi_de
28 Oct 2008, 2:04 AM
Hi! Thank you very much, posta!
/edit: no further question so far .
Michi_de
28 Oct 2008, 4:05 AM
To get more comfortable with MVC and Ext GWT i want to know something:
Lets imagine some realy easy application:
In the upper panel there are just 2 buttons, in the lower panel content will change. So how should i code this? The header panel wont change, while the content panel change its content each time a button in the header is clicked.
I dont think i should use more then one "view", should i?
But what does exactly the controller will do then? How to wire the buttons, to make sure each click will change the content of the lower panel?
And one of the thing what confuses me most:
If i implement a form into my content panel, how should i procede with the data inside there? This form is a widget i code myself (extends: FormPanel) and put it into the .widgets package. (just to keep it structured more)
So i have to put the RPC call inside this class? Wire the button with a method, do there the RPC call to save the data? Seems wrong to me... but the MVC doesnt help me at this point...
posta07
28 Oct 2008, 4:55 AM
n the upper panel there are just 2 buttons, in the lower panel content will change. So how should i code this?Well of course there are many variations of implementation, and I encourage anyone who has a solid way of doing this to comment, but I would do the following:
Controller c1 with two Views v1 and v2.
v1 has the two buttons you described.
v2 has the content to display.
Some Pseudo code
class Controller{
private View v1.
private View v2.
handleEvent(e){
if(e == init)
onInit
if(e == ChangeContent)
onChangeContent(e)
}
onChangeContent(AppEvent e) {
handle the processing on the models here (if there are any... for example, if you have a gird in the other view, handle operating on the store/models here, and the grid should automatically update itself)
forwardToView(v2, e)
}
}
v1 and v2 do not know about each other, only the controller knows about the two of them.
Upon clicking a button, v1 alerts the controller than a particular event has taken place and that it should service the event.
(At the moment the GXT framework doesn't allow for simple communication from view back to controller... so you'll probably need to fire an event with the dispatcher... see example:)
in the view with the buttons...
button.addSelectionListener(new SelectionListener<Button>() {
void componentSelected(Button b) {
Dispatcher.dispatch(AppEvents.ChangeContent);
}
});
This way you have separation between views (v1 can fire events only to the controller, while the controller services them.. v2 has no idea about v1 and doesn't need to)... the controller does its job to select what models get processed.... and any views that rely on the models get updated accordingly.
Does this make sense?
For your form panel example, the Controller should be doing the RPC calls.
Fire an event to your controller with the data you wish to save (see AppEvent.setData) and let the controller (or some agent/business agent) do the saving.
The MVC pattern helps your design stay flexible. In trivial cases you will not see much benefit from the MVC pattern. However, once your software becomes more in depth from the trivial case, you'll see that properly separating out your views and controllers will allow you to extend and modify your logic in a way that makes sense and doesn't break existing functionality.
You're on the right track!
Michi_de
28 Oct 2008, 6:21 AM
But how to bundle two diffrent views? As they are both displayed, but forwardToView only will wire one view...?
Should i first go for the header view, inside there start an event, which make the controller start enother event which generate the content panel?
posta07
28 Oct 2008, 6:36 AM
Put all of your code to initialize/instantiate views in your initialize() method (controller.initialize()) and also put your logic to display the views/organize widgets in the initialize() method (view.initialize()).
This initialize() method gets called before any action is taken on a controller or view.
Controller:
If you see in the mail sample app in com.extjs.gxt.samples.mail.client.mvc.MailController:
public void initialize() {
service = (MailServiceAsync) Registry.get("service");
folderView = new MailFolderView(this);
mailView = new MailView(this);
}
In your views, you'll be dealing directly with a widget that has already been added to the DOM, or you'll add new widgets. For example, in the mail sample, the AppController/AppView configures the layout for the Application, and creates a North, West, and Center (which are LayoutContainers) container.
In the com.extjs.gxt.samples.mail.client.mvc.MailView, widgets are being added directly to the Center container that was already created in AppView.
You'll see in MailView.initialize(), a container member variable is instantiated and configured:
@Override
protected void initialize() {
container = new LayoutContainer();
BorderLayout layout = new BorderLayout();
layout.setEnableState(false);
container.setLayout(layout);
mailListPanel = new MailListPanel();
container.add(mailListPanel, new BorderLayoutData(LayoutRegion.CENTER));
mailItemPanel = new MailItemPanel();
BorderLayoutData southData = new BorderLayoutData(LayoutRegion.SOUTH, .5f, 200, 1000);
southData.setSplit(true);
southData.setMargins(new Margins(5, 0, 0, 0));
container.add(mailItemPanel, southData);
}
In the handleEvent method, if a NavMail Event is fired, the View is adding the container member variable to the App's Center container...
protected void handleEvent(AppEvent event) {
if (event.type == AppEvents.NavMail) {
LayoutContainer wrapper = (LayoutContainer) Registry.get("center");
wrapper.removeAll();
wrapper.add(container);
wrapper.layout();
}
....
But how to bundle two diffrent views? As they are both displayed, but forwardToView only will wire one view...?So to answer your question, one view will add components to the top part of a "Center container", and the second view will add components to the bottom part of a "Center container."
Does this make sense?
Michi_de
28 Oct 2008, 11:59 PM
Well, the longer i read this the more i learn... its still not all clear to me, sorry :)
How to get an RPC goin? You said, the controller is gona do the call... so what i need now is to fill my member grid.
The ContentView.handleEvent will generate the custom Widget "MemberGrid" (extends ContentPanel ).
Should i make the widgets constructor like that:
MemberGrid(ListStore<Member> store) {..}
Or should i put a method inside the MemberGrid class:
void fillGrid(ListStore<Member> store) {...}
which update my grid?
I guess, considering the asynchronous calls, its better to use the second method? But how to get an RPC and make the grid filled with the data?
So far i just know, that the call can be done in a method the controller use (eg. onInit() {...} ).
On success it will do
Dispatcher.forwardEvent(AppEvents.NavMail, result);
The result is a "folder"... in the eventHandler is just this little thing:
case AppEvents.NavMail:
forwardToView(folderView, event);
forwardToView(mailView, event);
break;
so what?
I want to do something with a StoreList... not to change something that crucial like displaying a few... seems strange to me, how to work with such a call...
You are realy some great help for me! Thanks Posta!
And i don't think, im the only one who gets very usefull information here. 300 views so far in this topic ;)
posta07
29 Oct 2008, 4:47 AM
How to get an RPC goin? You said, the controller is gona do the call... so what i need now is to fill my member grid.Well, when you wire up your widgets, you'll definitely want to pass in your ListStore. I think it's best to wire it through the constructor as you mentioned before: this is because your gird will probably require a non-null store, so make it a required dependency for the constructor.
I prefer keeping the store (ListStore in your case) in the controller. A store is really just a catalog of models. What you'll need to do is wire up a GXT loader to your store and allow the controller to just call loader.load(). This will load the store (using RPC or whatever...). See com.extjs.gxt.samples.client.examples.grid.BeanModelGridExample.java (or any of the other gird examples that use RPC) to get an idea for how the proxy/loader/store examples work.
Here's pseudo code to (hopefully) help illustrate the above
class Controller {
private View v1;
private View v2;
private ListStore<ModelData> store;
private ListLoader loader;
public Controller(){
}
protected void handleEvent(AppEvent e){
...
if(e.type == AppEvents.LoadData)
onLoadData()
...
}
@override
protected void initialize(){
initStore();
View v1 = new View(this);
View v2 = new View(this, store);
}
private void initStore(){
RpcProxy proxy = new RpcProxy() {
@Override
public void load(...){
///
/// Your service methods here...(RPC call)
}
};
loader = new BaseListLoader(proxy); // if doing beanmodels use a BeanModelReader also
store = new ListStore<ModelData>(loader);
}
protected void onLoadData(){
// additional processing if necessary...
loader.load();
}
}
As long as you wire up your store to your grid, anytime the store changes (from the controller calling onDataChanged), your grid in your view will update automatically.
Michi_de
29 Oct 2008, 5:22 AM
Just a short question - not explicitely related to this topic.
My code to wire the RPC service looks like that:
ServiceDefTarget endpoint = (ServiceDefTarget) service;
String moduleRelativeURL = GWT.getModuleBaseURL() + "service";
endpoint.setServiceEntryPoint(moduleRelativeURL);
( the gwt.xml includes the right servlet spec:
<servletpath="/service"class="extGWTmvc.server.MemberServiceImpl"/>
)
But on module load i get
ClassNotFoundException: extGWTmvc.server.MemberServiceImpl
.... cant find any problem... :(
How to wire this all up? I think the error is in the .getModuleBaseURL() ?
When doing a breakpoint the String has this value:
http://localhost:9999/extGWTmvc.App/service
???
posta07
29 Oct 2008, 5:46 AM
It's tough to tell from the details you've given.
Mmm... if you zip up the project, I can take a look at the rpc problem later today.
Michi_de
29 Oct 2008, 5:56 AM
There is one more thing what bogus me:
View v2 = new View(this, store);
There is no such constructor? And why give the view a store?
and this is how my initStore() looks alike:
void initStore(){
RpcProxy proxy = new RpcProxy() {
@Override
publicvoid load(Object loadConfig, AsyncCallback callback) {
service.getAllUsers((BaseListLoadConfig) loadConfig, callback);
}
};
loader = new BaseListLoader(proxy);
store = new ListStore<Member>(loader);
}
is everything allright?
I dont realy get what the loadConfig does and why loader.load() do change anything on my list... why there is no documentation for so crucial stuff on ext gwt?
Here is my project.zip ...
posta07
29 Oct 2008, 8:26 AM
I saw two problems that may have caused the issue.
The first one is probably the major cause of your problem.
When GWT compiles to run, it does not compile any classes designated to run on the server side. In other words, your MemberServiceImpl.java class never got compiled.
The second issue is that in your App.gwt.xml file, you reference the serverlet class being in the extGWTmvc.server package, however you did not have any directory structure with that package.
Here's what I did:
I structured your app following the GWT guidlines. You're free to modify as you wish, or use it as the base structure. All code in the "client" directory is compiled by GWT when running, all code in the "server" directory you'll have to compile yourself. To that end, I added a simple ant build script that will compile your code. Modify the "build.properties" file that I've included to reflect the appropriate paths to GWT and GXT, and the ant file should work fine. I've also added an ant target that will run your GWT in hosted mode. To run that, type the following at command line:
(make sure ant is installed, on the path, and that you're in the directory with the build.xml file)
to build...
antto run hosted mode...
ant gwt-hosted
Good luck with your project! hope this helps!
Michi_de
29 Oct 2008, 11:21 PM
The problem seems solved, see below (dont waste too much time reading this post)..
Sorry, but this is just something i dont want to learn right now... i dont have the time to learn that much. All my GWT (and Ext GWT) projects were compiled like this:
in the client package the
service.class included the following code (pretty much after the implements):
@RemoteServiceRelativePath("submituser")
The gwt.xml file just had this tag too:
<servletpath="/submituser"class="extGWTformular.server.SubmitUserServiceImpl"/>
So what? It worked fine... why when using the MVC structure i've to use so crazy things i've never heared of? Ant build whatever?
Why the mail example uses this kind of code, to use RPC calls?
ServiceDefTarget endpoint = (ServiceDefTarget) service;
String moduleRelativeURL = GWT.getModuleBaseURL() + "service";
endpoint.setServiceEntryPoint(moduleRelativeURL);
Registry.register("service", service);
Why cant i just do it, like i explained above? Just make the @RemoteServletPath... thingy and gwt.xml <servlet> tag...? Is this just impossible in MVC ?
And is the mail example any different to my project? The gwt.xml file of the mail example includes this tag:
<servletpath="/service"class="com.extjs.gxt.samples.mail.server.MailServiceImpl"/>
?
It seems like the problem is solved now:
I put the "bin" folder into the classpath (run: configurations: classpath: add folder /bin in extGWTmvc)
So now everything is just fine! I got my rpc call workin, the data is receiving and i think i learned the mvc now :)
Maybe i will come back with some small questions... would be great if you could answer them too, if your not too busy.
Thanks!
Michi_de
5 Nov 2008, 12:14 AM
I hope there is still someone reading this topic, who could help me. I encounter a non trivial problem right now:
The controller initialize() method creates the views.
When a view gets instantiated, the widgets will be set. So i need to fill the grid widget with data, before it gets rendered.
So, before creating the views, the store needs to be filled with data.
The initialize() method of the controller does it:
RpcProxy proxy = new RpcProxy() {
@Override
publicvoid load(Object loadConfig, AsyncCallback callback) {
service.getAllUsers((PagingLoadConfig) loadConfig, callback);
}
};
loader = new BasePagingLoader(proxy);
loader.setRemoteSort(true);
loader.load(0,10);
store = new ListStore<Member>(loader);
toolBar = new PagingToolBar(10);
toolBar.bind(loader);
Everything is working fine.
But now i try to update the store.
The new data needs to be loaded from some other RPC call.
So what i tryd was store.removeAll(), then make a new RPC Proxy:
RpcProxy proxy = new RpcProxy() {
@Override
publicvoid load(Object loadConfig, AsyncCallback callback) {
service.getFilteredUsers((PagingLoadConfig) loadConfig, callback);
}
};
So now the proxy is using another service method.
After the store.removeAll(); i made the loader.load() again. So the new method will be used and the data from the new method gets used.
The only change i see is, the first page of my paginggrid dont have any data. But hitting the refresh button, the old data gets loaded.
So how to change the stores data?
I cant do just the store = new ListStore(loader);
Because the widgets store wont get changed in any way. I need to update the store the widget is using.
This seems pretty hard to me. Any help or solution?
zaccret
5 Nov 2008, 1:54 AM
Mmm. I'm not sure it's a good idea to create a new proxy. Why not just use your getFilteredUsers with an empty filter at first ? Then you just have to loader.load() (after a store.removeAll() ?) to refresh the grid.
Michi_de
5 Nov 2008, 2:08 AM
But i dont get allways to use the same method...
So i should get for all methods a store? Using different proxys and loaders?
Then again i would make the first call with a dummy filter, how should i change then the filter? By just editing the filters data?
Example:
on initialize() of controller, the
service.searchUser((PagingLoadConfig) loadConfig, user, callback);
will use "user" variable as the filter. Now this will be a dummy with no data. So i get the whole data.
Now in some later method i need to get user=xyz , how to do that? Just change the user variable? (as it is saved in the controller class anyway)
phamtranquocviet
14 Nov 2008, 7:53 AM
Hi,
In Explorer example, there are 3 controllers: AppController, ContentController, and NavigationController. All register AppEvent.Init. How does the dispatcher know which one to pick when running through the loop? I am asking because canHandle() function does not have any thing special to distinguish between the same event:
public boolean canHandle(AppEvent event) {
if (supportedEvents != null && supportedEvents.contains(event.type)) return true;
if (children != null) {
for (Controller c : children) {
if (c.canHandle(event)) return true;
}
}
return false;
}
Thanks.
Well, the same MVC principles you read on Wikipedia apply.
The GXT framework's MVC implementation follows the same rules... it's an request-driven (event-driven) MVC framework
...and instead of driven by an HTTP request like in other web-based MVC frameworks (like struts, spring, etc) the GXT's framework is driven by application events (see com.extjs.gxt.ui.client.mvc.AppEvent).
First you need to register controllers with the dispatcher.
From the explorer demo...
dispatcher = Dispatcher.get();
dispatcher.addController(new AppController());
dispatcher.addController(new NavigationController());
dispatcher.addController(new ContentController());When an event is fired by the dispatcher (see com.extjs.gxt.ui.client.mvc.Dispatcher), each one of the controllers are consulted to determine whether or not they can handle the event. (if the controller is not initialized, the initialize() method will be invoked). If a particular controller can handle the event, the controller's "handleEvent" method will be invoked.
Dispatcher Firing an event (from the explorer demo ):
dispatcher.dispatch(AppEvents.Init);
Dispatcher consulting controllers and initializing a controller if it's not initialized already:
(from com.extjs.gxt.ui.client.mvc.Dispatcher.java)
for (Controller controller : controllers) {
if (controller.canHandle(event)) {
if (!controller.initialized) {
controller.initialized = true;
controller.initialize();
}
controller.handleEvent(event);
}
}
You can see above that the dispatcher tells the controller to handle the event if the controller is capable of handling such events.
Once the controller's handleEvent method has been called, it's up the controller to determine what processing needs to occur, and which view should displaying the results.
In the case of the Explorer demo, the controller/views are trivial.... but following the same principles from any MVC discussion, the controller will be responsible for processing data (models) and the views should update.
I hope this is enough to help get an understanding... I purposefully wrote it to elicit questions and comments... feel free..
cheers
posta07
14 Nov 2008, 11:59 AM
How does the dispatcher know which one to pick when running through the loop?
The dispatcher will pick *all* of them if they all can handle the Init event.
I've started a blog to give back to the open-source community, and the first topic I've included is a tutorial of the Mail GXT reference app, with specific details about the MVC implementation. take a look:
http://www.christianposta.com/blog/
phamtranquocviet
14 Nov 2008, 3:03 PM
Posta07,
You blog helped me trace how exactly the login dialog appears at the beginning. I am so excited and ready to explore further. I am thinking of using a Eclipse UML plugin to do a reverse-engineering on Mail project (and others too). This will greatly help me trace everything at a glance and get a broader architectural picture of GXT. My searches show a bunch of plugins. Which one do you recommend? I am new to Eclipse.
Thanks.
EagleEye666666
15 Nov 2008, 10:34 AM
I've started a blog to give back to the open-source community, and the first topic I've included is a tutorial of the Mail GXT reference app, with specific details about the MVC implementation. take a look:
http://www.christianposta.com/blog/
From my side as well thanks for explaining the MVC of GXT in such a detailed way. I will implement my upcoming APP following the MVC pattern. I tried to understand the Explorer :D it was a massacre :D (biggest problem is to keep the overview cuz, the packages are quite mix and parted but in reference to each other > searching this and this class all over).
I am not new to developing and I already have done MVC Apps. So i guess i will manage it, with your Guide FOR SURE!
Thanks again! :)
Posta07,
You blog helped me trace how exactly the login dialog appears at the beginning. I am so excited and ready to explore further. I am thinking of using a Eclipse UML-plugin to do a reverse-engineering on Mail project (and others too). This will greatly help me trace everything at a glance and get a broader architectural picture of GXT. My searches show a bunch of plugins. Which one do you recommend? I am new to Eclipse.
Thanks.
uhm i have tried several things. For me nothing fitted at all. Right now iam using Omondo UML plugin... it has a free one as well(a few disadvantages like only usage for non-Team(SVN/CVS) projekts)
I don't like it at all. The biggest problem is for me that it is slowly and stuck a lot. Iam using several project facelets, Webapp+JPA+GWT+..... and to just create a simple class-diagram of my domain package with 4 Entity Objects is taking so a lot time. The most of the time you are just sitting and waiting while your CPU is working.
So from this side i would recommend it, but i haven't found a better FREE one yet. So I'm open as well to get to know new suggestions. :)
Anyway Eclipse is still best IDE for Java I LOVE IT! :D
posta07
15 Nov 2008, 3:46 PM
Which one do you recommend?
I like the one Darrell uses for GXT, I think it's called "yDoc"
http://www.yworks.com/en/products_ydoc.html
Unfortunately, it's not free.
phamtranquocviet
16 Nov 2008, 7:46 AM
As always, Thanks Posta07 for all the help you offered to me so far. My project is starting to take shape because of you. Thanks again.
EagleEye666666
17 Nov 2008, 9:48 AM
The dispatcher will pick *all* of them if they all can handle the Init event.
I've started a blog to give back to the open-source community, and the first topic I've included is a tutorial of the Mail GXT reference app, with specific details about the MVC implementation. take a look:
http://www.christianposta.com/blog/
Ok I have adopted my App to the MVC pattern. AWESOME :)
It took me a while to understand the samples ... cuz they have some not clear(the unchecked stuff) way of handling the events....
thanks for explaning the initialize() method :) this was the most helpful thing of your blog :D
phamtranquocviet
21 Nov 2008, 11:36 AM
Posta07,
I now have a decent understanding of how GXT implements MVC apps and am ready to write codes. Just want to consult with you on the architecture of my apps:
I want to:
- Login -> needs RPC here
- After sucessul login, display web desktop. Each of the five items on "Start" me fires off an explorer-example feature, which is also a MVC project.
Here is my plan:
- Create a wrapper project called "Main", which is a MVC application. After logging in, Main displays the desktop. So, desktop is part of the MVC-Main project. Each item on the menu fires off either a separate explorer-like or email functionality, which is also a MVC project but is not part of Main project.
My question is: Is it possible for a MVC project to fire off separate MVC apps? Note that: functionalities of a sub-projects is independent from the rest. Or all sub-projects (login, desktop, explorer, mail, etc....) must be in one single MVC project (Main) in order to catch events fired by the other members projects?
Thanks.
basix
22 Nov 2008, 7:34 PM
hey posta07, i'd like to learn more about the BaseModel and BaseTreeModel. I've done extensive reading on the MVC design pattern. I'm confused as to how to implement the "Model" Part using GXT. I've a few questions that need answering:
1. Is the Model object persistent and shared?
2. How do I identify Models necessary for my project?
3. How do I actually Model a Model?? What I mean is after identifying Models how do I design them? What are the essentials?
I'm trying to build a UI for a bidding portal. Its simple, I have "items", "categories" to put the items in and finally a "user". The user is allowed to modify his profile which consists of his username, password, nick. The items have bunch of properties such as name, price, location, etc... I understand that I'll need a UserModel and a ItemModel class.
Since I'm not clear about the implementation of Models I'm stuck up.
Another question pertains to the backend. I'm building the backend using PHP. I've got the basic classes done. I also have a script which can add, update and retrieve data in the database by processing form data. It returns the values to the front end using JSON encoding. Whats the best way to integrate the RPC Calls with the frontend? or more specifically how should I go about designing the components who make the RPC calls and update the data on the frontend?
Thanks! :)
posta07
24 Nov 2008, 10:07 AM
phamtranquocviet,
It might be kind of sticky for your situation to use MVC to try and communicate between separate modules... you'll probably need to create some sort of custom implementation of an IPC as I don't think GXT or GWT provides out-of-the box functionality for this:
http://en.wikipedia.org/wiki/Interprocess_communication
basix,
it sounds like you need a good object-oriented modeling tutorial. do a google search for "domain model" or "model driven development" or "object oriented modeling." there has been a lot of information on how to conceptualize and then materialize domain models.
I can try to give a very quick and dirty overview and answer your questions at the same time.
Is the Model object persistent and shared?
The simple answer is, yes, model objects can be persisted and shared between the different layers of your application. GWT RPC gives the developer the opportunity to use fine-grained plain-old-java objects (POJOs) without much consideration to the serialization of those objects. However, I believe you must have a java back end for that. If you're using PHP, you'll have to use a different serialization implementation to share the objects (JSON or XML works).
How do I identify Models necessary for my project?
Definitely start with a google search. I think you have the basic idea of how to identify models (user, item, category, etc for your portal are perfect examples of models). Models are generally simple objects with fields and getter/setter methods to change the value of those fields. They represent a business artifact (usually a "noun").
How do I actually Model a Model?? What I mean is after identifying Models how do I design them? What are the essentials?
Exactly as I stated above. You can make them simple objects with properties (like you mentioned: name, price, etc) and with simple getter/setter methods ... (getPrice(), setName(String..) etc.). Once you have the business object modeled, you can add behavior to the model if you wish (for the Item model, for example, you can add a calculatePrice() method to perform business rules for calculating the price). Generally, your model objects should be fairly simple, but they should identify the relationships between the objects and identify their respective properties.
For you last question, I would look into GXT's JSON reader classes ( in the com.extjs.gxt.ui.client.data package) to help convert the JSON serialization to model objects. You can use plain old java objects for your models, or the BaseModel / BaseTreeModel classes. I would recommend using plain old java objects.
Hope this helps!
basix
24 Nov 2008, 10:50 AM
Hi posta07,
thanks for the insightful post. I'm still unable to understand what is a BaseModel and BaseTreeModel? Whats their purpose? And how are they used?
I've been trying hard to implement MVC using GXT but I'm clueless at this point as to what the heck is wrong with my implementation. Briefly, I'm trying to build a "menu". This is just to get the hang of the GXT MVC implementation.
This is my idea of implementing a Menu. It has MenuItems, they can be added, removed. When a MenuItem is added, the view updates itself. Heres how I've broken it up:
1. MenuModel - extends BaseTreeModel and has a method addItem() to add a menu item. getItems() returns all the menu items currently in the model. Only one object of this model is instantiated and is stored in the Registry.
2. MenuView - extends View and implements ChangeListener. It has 3 methods: initialize(), handleEvent(), modelChanged(). The initialize method gets the instance of the MenuModel from the Registry and calls addChangeListener( this ). The handleEvent() doesn't do anything. the modelChanged() function "updates" the menu when the model is changed.
3. MenuPanel - this is the class which actually defines how the Menu looks. It has an updateMenu() method which is called when MenuView's modelChanged() function is called.
4. MenuController - it extends Controller and has initialize() method which instantiates a MenuView object. It has handleEvent() method which forwards the AppEvents.Init event to MenuView.
5. AppEvents - this class simply stores all event types.
6. tApp - this is the entry point of my application. It creates a MenuModel object and stores it in the registry, then creates the MenuController and adds it using Dispatcher.addController() and finally, it dispatches the AppEvents.Init event.
What could be the issue? Is my understanding wrong?? I'm also attaching the code so you can see for yourself what could be wrong.
Thanks!
posta07
24 Nov 2008, 2:56 PM
From what I understand, and please some one add to this where they see fit, the BaseModel and BaseTreeModel are the classes that the GXT components use to display data. For example, ComboBoxes requires models that extend ModelData, tree widgets require their models extend from ModelData, and you'll notice other components (Store) require ModelData objects.
In other words, these "model" objects are used by the GXT components.
Your "model" objects are usually plain old java objects without any dependencies on any framework. This means there are (at least) two ways to work with the GXT framework: Convert your POJOs to GXT objects when data is coming to the client (and then converting the GXT models back to your POJO when sending to the server), or just use your POJO with the GXT BeanModelReader (which allows you to use your POJOs directly with the GXT components).
My suggestion:
Always write your business/domain objects with POJOs. These are usually basic classes with some properties, getters/setters, and business logic and DO NOT have dependencies on any 3rd party/external frameworks.
Does this adequately answer your questions?
basix
24 Nov 2008, 3:45 PM
Yes for the BaseModel, BaseTreeModel it does. But I'm still unclear about how Models are used in the GXT MVC implementation. Did you take a look at my code?
phamtranquocviet
25 Nov 2008, 11:31 AM
phamtranquocviet,
It might be kind of sticky for your situation to use MVC to try and communicate between separate modules... you'll probably need to create some sort of custom implementation of an IPC as I don't think GXT or GWT provides out-of-the box functionality for this:
http://en.wikipedia.org/wiki/Interprocess_communication
Posta07,
First, thanks for the clarification. Second, are you aware of any performance issues when lumping all sub-projects into one single MVC app because the controller list might grow pretty fast for a big application like the one I am planning to write. My search in the gxt forum does not show any trace of this potential issue.
Thanks.
zaccret
26 Nov 2008, 2:18 AM
Second, are you aware of any performance issues when lumping all sub-projects into one single MVC app because the controller list might grow pretty fast for a big application like the one I am planning to write. My search in the gxt forum does not show any trace of this potential issue.
I don't understand what you call "sub-projects". As phamtranquocviet said, one GWT app = one module. A GWT module cannot communicate with another module.
Anyway, I know you can add children (controllers) to a parent controller but I don't know if it reduces the dispatcher loop.
posta07
26 Nov 2008, 7:29 AM
But I'm still unclear about how Models are used in the GXT MVC implementation. Did you take a look at my code?Yes, I looked at your code. First it threw a ClassCast exception because you're code to add a list was actually adding a string; once I fixed that (see below), I was able to see what your code was doing.
public void addItem( String e ) {
entries.add( e );
set( "entries", entries ); // you were adding 'e'
}
Everything else was good!
Michi_de
12 Dec 2008, 12:39 AM
Sorry Posta, for disturbing you again.. but i've got a problem with my applicatioin which i realy can't solve.. i guess the problem happens, because my application is designed this way, that on the most content-events the content in the "center" (a layout container) gets removed and the new content gets added. This way the grid widgets, which have been removed once and put again inside the "center", they get broken.
Here is a more detail explanation of the problem, in the last post you can see some pictures of the application, so you maybe can better imaginate my application/problem.
http://extjs.com/forum/showthread.php?t=54447
I put the .client package out of my application into a zip file, so maybe if you have some free time and feel like helping me, take a look at them please:
posta07
16 Dec 2008, 4:54 PM
I have looked at your code, but it is in a state that I cannot compile and run. Is it possible for you to re-create this problem using a simple code snippet that follows the guidelines suggested by Darrell?
http://www.extjs.com/forum/showthread.php?t=33778
Michi_de
17 Dec 2008, 2:51 AM
Ok, here we go (it took me almost 2 hours to put this new application together, i realy made it as easy and clear as i could).
Thank you so much for everything you done so far :)
Its some easy MVC application, in order to get some grids.
Try sort and resize the grid, then hit a button and try it again. And then go back again to another grid.
As a grid is the first time shown, it works good. After a second time its up on top, its broken.
/edit:
Don't get me wrong! Sorting the grid in the "price" column does not make the grid sort, because i did some small error in the "compare" method in the sorting... This is a small bug i can fix by my own.
The bug i am talking about the whole time, is when u try to sort/resize the table then go to another table (by clicking the button) and then go back to the first table (click button again) will make the grid doesn't react anymore to any mouse clicks.
Michi_de
8 Jan 2009, 4:23 AM
Anybody? Is this problem to "hard" to understand? :(
If it realy is, then tell me so.
I think its pretty clear... just download the project and run it.
Try to sort the grid and then click the button and sort again, and then do it one more time. U should see the problem then...
Please help me...
I guess you should try in the Help forum instead of Open Discussion.
posta07
8 Jan 2009, 8:21 PM
I have downloaded and tried your source code. You will need to explain a little more clearly what problem you're getting. I tried your grids out, and everything seems to work fine for me. I am using the latest GXT build, Windows Vista, Gwt 1.5.2.
I click the column header to resize a column. I then go to the second grid. I then resize a column there. When I go back to the first grid, everything works as expected.
Where are you seeing an issue?
Edit: I've tried all kinds of combinations of sorting/resizing the columns from both grids. I still do not see any abnormalities.
Michi_de
8 Jan 2009, 11:19 PM
Now this is realy strange.
I use gwt-windows-1.5.2 and gxt-1.1.1 (aren't this the latest releases? ).
My IDE is Eclipse Platform Version: 3.4.1 .
My OS is Windows XP - SP 2.
The JDK installed is jdk1.6.0_07 .
And when i start the application in hosted mode i just need to do following:
- resize the columns or sort the grid => works correct
- click "show new grid" button
- resize the colums or sort the grid => works correct
- click "old grid" button
- resize the colums or sort the grid => nothing works anymore
So how could this be? Why is this only an issue for me? :-?
This seems very weird...
gslender
8 Jan 2009, 11:25 PM
I use gwt-windows-1.5.2 and gxt-1.1.1 (aren't this the latest releases? ).
Current release for GWT is 1.5.3 and current release for ExtGWT is 1.2.1
Michi_de
8 Jan 2009, 11:31 PM
So now i updated my libraries and still got this bug.
:-?
I did everything correct by just adding new user librarys into my eclipse?
as u can see here:
Michi_de
9 Jan 2009, 12:30 AM
I have an idea what we could test:
any of you, who say this code is working fine, could be so kind to compile the application into a html site with js, so i can just open it with my IE or FF explorer?
Just compile it and put into a zip archive, i will test it then.
Maybe its my browser, what make this grid buged? (why the hosted mode browser also has this bug, i dont know ... =C )
Michi_de
11 Jan 2009, 10:45 PM
I just realised that its not working when the appliction is just compiled. The servlets need the correct server, to get the data from RPC. ...
So how strange is this? Why on my pc there is this bug and on yours not? I use the same GWT and GXT now (as you can see in one of my last posts attachments).
I realy need to solve this problem....... please, anybody could help me?
EagleEye666666
12 Jan 2009, 1:44 AM
I just realised that its not working when the appliction is just compiled. The servlets need the correct server, to get the data from RPC. ...
So how strange is this? Why on my pc there is this bug and on yours not? I use the same GWT and GXT now (as you can see in one of my last posts attachments).
I realy need to solve this problem....... please, anybody could help me?
Ok for you i will try your app. even i have no time ...
I tried it, for me it works (except your mentioned bug with the sort of the price) GWT 1.5.3 / GXT 1.2.1 / Linux / Java6 ..
I just add project and started hosted mode. new grid, old grid ... no problem here switching them. It is hard to find your WELL defined PROBLEM in all this threads. maybe you should clarify that somewhere, maybe 1more ppl could respond. Because i just guess that this switching the grid there is your problem?
Michi_de
13 Jan 2009, 6:39 AM
Problem solved:
I forgot to put the new User Libraries into the startup in Eclipse. I just had them in my application, but eclipse still run my application with old version files.
Now that i changed this, there is no grid bug anymore.
Hooray!! :D
EagleEye666666
13 Jan 2009, 7:12 AM
Problem solved:
I forgot to put the new User Libraries into the startup in Eclipse. I just had them in my application, but eclipse still run my application with old version files.
Now that i changed this, there is no grid bug anymore.
Hooray!! :D
omg =D>
Powered by vBulletin® Version 4.1.5 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.