PDA

View Full Version : ExtJS Client



sagarsgiri
16 Aug 2011, 4:16 PM
Hi,
I am a new to ExtJS. We have built an application, that has server-side written in Java (RESTful) and a flex client.
I want to design a ExtJS client that talks to the Jetty server and uses REST to GET and POST the user login details to the backend oracle DB. I have been trying to figure out the right approach, but I am right where I started.
Is there any example that I can refer to?

Thanks in advance.

mberrie
16 Aug 2011, 6:16 PM
As a starter, you might want to create a login form

http://docs.sencha.com/ext-js/4-0/#/api/Ext.form.Panel

and then use an Ajax request to authenticate

http://docs.sencha.com/ext-js/4-0/#/api/Ext.Ajax

skirtle
16 Aug 2011, 6:21 PM
If I've understood correctly, you've got a Jetty server that hosts the web app. Behind that you've got an Oracle database. Correct?

Assuming I've understood correctly, the first thing to note is that your choice of DB is pretty much irrelevant from an ExtJS perspective. ExtJS will only be communicating with Jetty.

Presumably allowing users to authenticate isn't the limit of your desired functionality? Do you intend to have every request from the browser pass authentication details or do you intend to use some form of session cookie, such that authentication is only done once?

For the session cookie approach this should be quite simple. Just fire off an Ajax request using Ext.Ajax.request(). On the server you then authenticate the user and, assuming they pass, create a session (something like request.getSession() I believe it is in Java). That's it. The session cookie will automatically be sent back to the browser and all subsequent requests will include that cookie. Any information you store on the server's session object will persist between requests.

Make sure you've got good developer tools installed before you start down the ExtJS path. If you're using Firefox then get Firebug installed, or use the Chrome Developer Tools if you prefer Chrome. These tools have all sorts of useful things but for the task at hand the ability to watch the HTTP requests will prove very useful.

sagarsgiri
16 Aug 2011, 6:49 PM
Thanks for the quick reply.
I am going through the Sencha docs right now.

Your assumption is right. The set of username's and password's are stored in the DB. I just have to design a ExtJS client that communicates with the Jetty server.

These are the steps :
1. Once the user enters the details (user id and pwd) and clicks login,
2. I have to fetch those details and send it in a JSON object to the server-side for processing (authentication)
3. After auth, I get a response JSON object that contains all the information wrt the user (the complete row), which I have to display in a Grid on the browser.

I referred to the following post:
http://stackoverflow.com/questions/2912118/how-to-generate-json-object-on-client-side-and-send-it-to-server

Thanks again.

skirtle
16 Aug 2011, 7:07 PM
The answers on that Stack Overflow thread look pretty sensible to me. You don't actually need to use Ext.encode() if you include it as jsonData, that'll happen automatically.

The only thing I'd add is that sending the data to the server a JSON post body is a little overkill for just a username and password, normally you'd just send them as 2 request parameters. That said, if you've already written your server or you intend for all requests to use a JSON payload then this won't be any extra effort for you.

sagarsgiri
17 Aug 2011, 10:58 AM
As a starter, I am loading the login.js FormPanel using index.html. When I click login I want to send the request using the Ext.Ajax.request in index.js.
I know I am doing something really stupid. Please help me.

login.js
Ext.onReady(function(){
Ext.QuickTips.init();
var login = new Ext.FormPanel({
labelWidth:90,
url:'index.js',
frame:true,
title:'Please Login',
defaultType:'textfield',
monitorValid:true,


items:[{
fieldLabel:'Username',
name:'loginUsername',
allowBlank:false
},{
fieldLabel:'Password',
name:'loginPassword',
inputType:'password',
allowBlank:false
}],

buttons:[{
text:'Login',
formBind: true,
// Function that fires when user clicks the button
handler:function(){
login.getForm().submit({
method:'POST',
waitTitle:'Connecting',
waitMsg:'Sending data...',

success:function(){
Ext.Msg.alert('Status', 'Login Successful!', function(btn, text){
if (btn == 'ok'){
var redirect = 'test.js';
window.location = redirect;
}
});
},

failure:function(form, action){
if(action.failureType == 'server'){
obj = Ext.util.JSON.decode(action.response.responseText);
Ext.Msg.alert('Login Failed!', obj.errors.reason);
}else{
Ext.Msg.alert('Warning!', 'Authentication server is unreachable : ' + action.response.responseText);
}
login.getForm().reset();
}
});
}
}]
});

var win = new Ext.Window({
layout:'fit',
width:250,
height:125,
closable: false,
resizable: false,
plain: true,
border: false,
items: [login]
});
win.show();
});



index.js
Ext.Ajax.request({
url : 'http://localhost:8089/user/access/',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
jsonData: {"userName": "loginUsername",
"password": "loginPassword"}


success: function (response) {
var jsonResp = Ext.util.JSON.decode(response.responseText);
Ext.Msg.alert("Info","UserName from Server : "+jsonResp.userName);
},
failure: function (response) {
var jsonResp = Ext.util.JSON.decode(response.responseText);
Ext.Msg.alert("Error",jsonResp.error);
}
});



Thanks in advance.

stevil
17 Aug 2011, 2:30 PM
Are you seeing the request go out, and/or getting a JSON response at all? I'm trying to get to whether or not any parts of this are working.

stevil

sagarsgiri
17 Aug 2011, 2:37 PM
The request is not going out.

Exception on firebug -
uncaught exception: You're trying to decode an invalid JSON String.

skirtle
17 Aug 2011, 2:55 PM
A few initial thoughts.

Firstly, please use code tags whenever you post code (# button on the editor toolbar).

Next, Firebug will tell you exactly which line blew up. Just look down the stacktrace for the line in your code that tries to decode some invalid JSON. I could guess which line it is but it's much easier for you to spend 10 seconds looking at a stacktrace then for us to start speculating.

This line seems a bit odd to me:


url:'index.js',

This also doesn't seem right, it won't extract the field values, it'll send exactly those strings:


jsonData: {"userName": "loginUsername",
"password": "loginPassword"}

I also wonder whether you're trying to mix two different approaches: page submits and Ajax. You can combine the two but it's more common to pick one or the other.

You also seem to be using the old ExtJS 3 names for everything. FormPanel is now Ext.form.Panel, Window is Ext.window.Window. I recommend familiarizing yourself with the docs for the components you're trying to use:

http://docs.sencha.com/ext-js/4-0/

Understand every config setting and method you use: it can be painful at first but it's worth it.

sagarsgiri
17 Aug 2011, 3:16 PM
Thank you.

stevil
18 Aug 2011, 6:16 AM
The request is not going out.

Exception on firebug -
uncaught exception: You're trying to decode an invalid JSON String.

index.js returns code, not JSON, that's why you're getting the decode error.

stevil

sagarsgiri
19 Aug 2011, 3:27 PM
Hi,

I have been doing this for almost a week now. Still haven't figured it out.
Please help.



Ext.require([
'Ext.form.*'
]);

Ext.onReady(function(){
Ext.QuickTips.init();

var login = Ext.create('Ext.form.Panel',{
labelWidth:80,
url:'http://localhost:8995/login/access/open', //url - jetty server
method:'POST',
frame:true,
title:'Please Login',
defaultType:'textfield',
monitorValid:true,

items:[{
fieldLabel:'Username',
name:'userName',
allowBlank:false
},{
fieldLabel:'Password',
name:'password',
inputType:'password',
allowBlank:false
}],

buttons:[{
text:'Submit',
formBind: true,

handler:function(){
var form = this.up('form').getForm();
if(form.isValid())
{

Ext.Ajax.request({
url:'http://localhost:8995/login/access/open',
method: 'POST',
headers: {'content-type':'application/json'},
jsonData:{ "userName":this.up('form').getValues().userName,
"password":this.up('form').getValues().password,

},
success:function(response,request){
obj = Ext.util.JSON.decode(response.responseText);
Ext.Msg.alert('Status', 'Success', obj);
},
failure:function(response,request){
if(action.failureType == 'server'){
obj = Ext.util.JSON.decode(response.responseText);
Ext.Msg.alert('Failure', obj.errors.reason);
}else{
Ext.Msg.alert('Reason', 'Caused by :' +response.responseText);
}

}
});
}
}


}],
//renderTo: Ext.getBody()
});
var win = Ext.create('Ext.window.Window',{
layout:'fit',
width:300,
height:250,
closable: false,
resizable: false,
plain: true,
border: false,
items: [login]
});
win.show();
});



I tried a different approach, got the same exception:


var obj1 = {"userName":this.up('form').getValues().userName,
"password":this.up('form').getValues().password};

params : {json: Ext.util.JSON.encode(obj1)},


Error in firebug (Console + Net results):


i.getAllResponseHeaders() is null

chrome://firebug/content/blank.gif

(function(){var e=this,a=Object.protot...ate("Ext.XTemplate",j,g)}return j}}); (http://www.sencha.com/forum/"%7Bhref%7D")ext-all.js (line 15)




Response Headers



Content-Length
0


Server
Jetty(6.1.25)








Request Headers



Host
localhost:8995


User-Agent
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110429 CentOS/3.6-1.el5.centos Firefox/3.6.17


Accept
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8


Accept-Language
en-us,en;q=0.5


Accept-Encoding
gzip,deflate


Accept-Charset
ISO-8859-1,utf-8;q=0.7,*;q=0.7


Keep-Alive
115


Connection
keep-alive


Origin
http://localhost:8080


Access-Control-Request-Me...
POST


Access-Control-Request-He...
x-requested-with










Error on the server side:


Aug 19, 2011 4:11:18 PM com.sun.jersey.spi.container.ContainerResponse traceException
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException: javax.xml.bind.JAXBException: class com.sun.research.ws.wadl.Application nor any of its super class is known to this context.
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:152)
at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:294)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1140)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1053)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1043)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:406)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:477)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:662)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:216)
at com.google.inject.servlet.ServletDefinition.service(ServletDefinition.java:141)
at com.google.inject.servlet.ManagedServletPipeline.service(ManagedServletPipeline.java:93)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:63)
at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:122)
at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:110)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:322)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: javax.xml.bind.JAXBException: class com.sun.research.ws.wadl.Application nor any of its super class is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:565)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:481)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:325)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:254)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
at com.sun.jersey.json.impl.JSONMarshallerImpl.marshal(JSONMarshallerImpl.java:71)
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:172)
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:150)
... 27 more



Thank you for your time.

skirtle
22 Aug 2011, 3:40 PM
I don't know what's causing your problem but I can attempt some advice on how to debug it.

Firstly, from everything you've described it sounds like your server isn't behaving correctly. There's not much point attempting to tackle the ExtJS side of things until the server is behaving (or at least giving a suitable fake response). I've given a few pointers on how to approach this but fundamentally this has nothing to do with ExtJS so it isn't really an appropriate discussion for this forum.

Try to open up the server by disabling any security stuff you've added. This may not apply in your case. Many apps disable GET requests or add filters that block based on referer headers or the like. Turn all of this off. Get the server responding to requests sent from the browser address bar. Don't turn on 'security' features until the basic login process works.

If that isn't possible, use something like cURL make requests instead. You need to be in a position where you are sure that the server works correctly in isolation. You shouldn't need to post issues with stacktraces from both the server and the client.

Another way to approach this is to create a mock server response. Rather than pointing ExtJS at the real login URL, put a static page on your server that has a fake response in it. It obviously won't work properly (it won't be possible to set a cookie for starters) but it should allow you to test the majority of your JS code.

Next, you appear to be trying to debug using a minified version of ExtJS. For development you shouldn't be using ext-all.js. Use ext-all-debug.js instead. That way you'll get intelligible stacktraces, meaningful line numbers and code you can put breakpoints in. JavaScript debugging tools are actually quite powerful, make sure you're familiar with how to use them properly (I highly recommend the Chrome Developer Tools as an alternative to Firebug).

You've posted various bits of info from Firebug but you've actually left out the most important bits. What was the URL and what were the request parameters? Were those parameters included on the GET request or the POST body? Does this tie up with what the server is expecting?

From the Firebug output you've quoted it seems the response is 0 bytes. Is this what you would expect for a sucessful request? Assuming it isn't you need to answer one simple question: is the request wrong or is the response wrong. Your ExtJS code builds the request, the server builds the response. Answering that question will tell you where the (first) problem is. Everything you need to answer that question is available in Firebug.

sagarsgiri
22 Aug 2011, 4:45 PM
Thank you.

Sorry, I was impatient. I have a presentation tomorrow and wanted to finish the client as soon as possible.

Whenever I send a cURL to the server, I get back the response.

When I set the URL in Ext.Ajax.request as -
url : 'http://localhost:4567/login', JSON is not created, hence the error on the server side.
Whereas when I enter the URL as - /login, JSON is created. (I checked this in Firebug as well as in Chrome)

My question is how do I specify the port where the server is running?

In Sproutcore we add this as a proxy in the Buildfile
proxy : '/login' => 'localhost:4567'

Is there a way I can do something like that in ExtJS?

skirtle
22 Aug 2011, 4:57 PM
ExtJS is restricted by the browser's same origin policy:

http://en.wikipedia.org/wiki/Same_origin_policy

In short, the only server you can contact is the one in the browser's address bar. The server and port must match exactly. It doesn't matter where the other files come from, such as the JS files, just the URL in the address bar. The only standard workaround is to use JSON-P but that has many limitations.

Effectively this makes specifying the port of the server a moot point as only the port of the current page is permitted anyway.

If http://localhost:4567 is the right origin for your page then you should be able to use it in your request. If you can't it may be a bug. That said, it's surely trivial to work around this just by specifying it as '/login' instead.