Configure the DataSource:
To do this you will need to configure a jetty-web.xml file and place it in your Web Application’s WEB-INF directory. Details on how to do this for various databases are located on the Jetty Documentation site at http://docs.codehaus.org/display/JETTY/DataSource+Examples.
NOTE: I believe the version of jetty shipped with GWT is below 6.1.12 and therefore you must leave off the first parameter in the example docs as it was added in jetty 6.1.12rc3. See the note at the top of the Jetty documents page.
A Sample jetty-web.xml file for connecting to a local mysql server follows:
<?xml version=”1.0”?>
<!DOCTYPE Configure PUBLIC “-//Mort Bay Consulting//DTD Configure//EN” “http://jetty.mortbay.org/configure.dtd”>
<Configure class=”org.mortbay.jetty.webapp.WebAppContext”>
<New id=”website” class=”org.mortbay.jetty.plus.naming.Resource”>
<Arg>java:comp/env/jdbc/database</Arg>
<Arg>
<New class=”com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource”>
<Set name=”Url”>jdbc:mysql://localhost:3306/database</Set>
<Set name=”User”>(Username)</Set>
<Set name=”Password”>(Password)</Set>
</New>
</Arg>
</New>
</Configure>
Configure the Eclipse Run Configuration:
Open the Eclipse run configuration and select the “Arguments” Tab. Then under “VM arguments“ section add the following:
-Djava.naming.factory.initial=org.mortbay.naming.InitialContextFactory
Acquire a Database Connection:
You should now be able to make a JNDI lookup to retrieve the datasource:
public Connection retrieveConnection() throws Exception {
Connection lConnection = null;
Context lContext = new InitialContext();
DataSource lDataSource = (DataSource) lContext.lookup("java:comp/env/jdbc/database");
lConnection = lDataSource.getConnection();
return lConnection;
}
Resource Injection:
Supposedly Jetty supports the servlet 2.5 specification and resource injection via the web.xml entry or @resource annotation. However, I have yet to figure out if this is supported by the Jetty version shipped with GWT. If anyone has figured out whether or not this works and if so how it is done please let me know.
38 comments:
Thank you for posting this info. However, I'm having a bit of trouble with your example. When I run mine, I get an error:
java.lang.ClassNotFoundException: org.mortbay.jetty.plus.naming.Resource
It appears as though this isn't on the classpath by default. Did you have to add a jetty jar?
Yes, you will need to copy the jars jetty-plus-1.6.11.jar, and jetty-naming-1.6.11.jar into your project classpath for this to work.
thanks I need this so bad. :D
Thank you sir.
Hi, I'm new to this approach to database connection and have a quick question about this:
Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/database");
connection = dataSource.getConnection();
when dataSource.getConnection() is called is an entirely new connection made to the server (slow) or does the initial connection only happen once and each repeat call of .getConnection() get the previous connection from the session?
@Adam:
I suppose it depends on your datasource driver, but typically a new connection will be created each time. Of course it depends if your datasource is a pooling one or not...
Main point is, you should always dispose of the connection properly after using it (connection.close())
I agree with Tim. Whether or not a new connection is created each time depends on how you configure the datasource in your server.
The http session is not used for the database connection.
It has been a long time since I have seen stats, but in the past (and I would assume still) the most costly portion of using a database, with regard to time, was the establishment of the connection. For deployment I would recommend setting up a database pool, but the setup I describe does not as it is sufficient for our development purposes.
Thanks for the post.
I need to incorporate a JCA Resource Adapter in a similar fashion. I tried modifying your instructions, but get a ClassNotFoundException. It seems that Jetty doesn't know about classes in package javax.resource.cci?
Do I need to include the jars mentioned by Chad Skinner: jetty-plus-1.6.11.jar and jetty-naming-1.6.11.jar?
If so, are they obtained from the Jetty site, or are they included in the GWT release?
It's my server side code
package de.MyFirm.gwt.server;
import javax.sql.DataSource;
import java.sql.Connection;
import javax.naming.InitialContext;
import javax.naming.*;
import org.mortbay.jetty.servlet.Context;
import de.netup.gwt.client.GreetingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
/**
* The server side implementation of the RPC service.
*/
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
public String greetServer(String input) {
String serverInfo = getServletContext().getServerInfo();
String userAgent = getThreadLocalRequest().getHeader("User-Agent");
String s1 = "";
Context context = new InitialContext();
DataSource dataSource = (DataSource)context.lookup("java:comp/env/jdbc/myDB");
Connection con = dataSource.getConnection();
con.close();
return "Hello, " + input + "!
I am running " + serverInfo
+ ".
It looks like you are using:
" + userAgent + "
ticketMaschine: " + s1;
}
}
I've got following error messages:
- Type mismatch: cannot convert from InitialContext to Context
- The method lookup(String) is undefined for the type Context
Thanx a lot,
andrash
You have imported the wrong Context class it should be:
import javax.naming.InitialContext
import javax.naming.Context
-Not-
import org.mortbay.jetty.servlet.Context;
Give this a try and let me know whether it solves your issue.
Now I've been getting following error messages:
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.lookup(Unknown Source)
at de.netup.gwt.server.GreetingServiceImpl.greetServer(GreetingServiceImpl.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:527)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:166)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java:86)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:205)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
If you are running this from eclipse you will need to set the System Property defining the initial context factory in the launch configuration
-Djava.naming.factory.initial=org.mortbay.naming.InitialContextFactory
Can you tell me what server you are running this in?
How can I execute this statment(I'm a beginner)?
-Djava.naming.factory.initial=org.mortbay.naming.InitialContextFactory
How are you running the code and what server are you running on, are just running the hosted mode? I need to know more about what you are doing in order to help.
Can I send an e-mail to you? It were the easiest way.
I'm using the standard starter code "Greetserver" of GWT. And thus I send just my server side code to you:
package de.netup.gwt.server;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import de.netup.gwt.client.GreetingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
/**
* The server side implementation of the RPC service.
*/
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
public String greetServer(String input) {
String serverInfo = getServletContext().getServerInfo();
String userAgent = getThreadLocalRequest().getHeader("User-Agent");
String s1 = "No OK";
try {
Context context = new InitialContext();
try {
DataSource dataSource = (DataSource)context.lookup("java:comp/env");
try {
Connection con = dataSource.getConnection();
try {
con.close();
s1="OK";
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (NamingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "Hello, " + input + "!
I am running " + serverInfo
+ ".
It looks like you are using:
" + userAgent + "
DB Connection: " + s1;
}
}
How can I publish my web.xml and jetty-env.xml? I don't want big modifications on both xml's.
What email address do you want me to use to contact you?
Also, The problem is not with your code, but with the fact the jetty server used for hosted mode does not have a JNDI ContextFactory Configured.
What IDE are you using for development? (Eclipse?)
jetty-env.xml
?xml version="1.0"?>
configure class="org.mortbay.jetty.webapp.WebAppContext">
!-- new class="org.mortbay.jetty.plus.naming.EnvEntry">-->
!-- arg>meinEnvParameter /arg>-->
!-- arg type="java.lang.String"> /arg>-->
!-- arg type="boolean">true /arg>-->
!-- /new> -->
new id="jdbc/DS" class="org.mortbay.jetty.plus.naming.Resource">
arg>jdbc/DS /arg>
arg>
!-- com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource -->
new class="com.mysql.jdbc.Driver">
Set name="Url">jdbc:mysql://kaltenberg2.ticketmachine.net:3306/ /Set>
set name="User">testbenutzer /set>
set name="Password">test /set>
set name="DatabaseName">sandrar /set>
/new>
/arg>
/new>
/configure>
Please check one more time my server side code, because I have changed it
*******************
web.xml
*******************
?xml version="1.0" encoding="UTF-8"?>
!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
web-app>
!-- Servlets -->
servlet>
servlet-name>greetServlet /servlet-name>
servlet-class>de.netup.gwt.server.GreetingServiceImpl /servlet-class>
/servlet>
servlet-mapping>
servlet-name>greetServlet /servlet-name>
url-pattern>/p7/greet /url-pattern>
/servlet-mapping>
resource-ref>
description>MySQL Connection /description>
res-ref-name>jdbc/DS /res-ref-name>
res-type>javax.sql.DataSource /res-type>
res-auth>Container /res-auth>
/resource-ref>
!-- Default page to serve -->
welcome-file-list>
welcome-file>P7.html /welcome-file>
/welcome-file-list>
/web-app>
*******************
server side code
*******************
package de.netup.gwt.server;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import de.netup.gwt.client.GreetingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
/**
* The server side implementation of the RPC service.
*/
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
public String greetServer(String input) {
String serverInfo = getServletContext().getServerInfo();
String userAgent = getThreadLocalRequest().getHeader("User-Agent");
String s1 = "No OK";
try {
Context context = new InitialContext();
try {
DataSource dataSource = (DataSource)context.lookup("java:comp/env/jdbc/DS");
try {
Connection con = dataSource.getConnection();
try {
con.close();
s1="OK";
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} catch (NamingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "Hello, " + input + "!
I am running " + serverInfo
+ ".
It looks like you are using:
" + userAgent + "
DB Connection: " + s1;
}
}
*******************
Note! I had to replace the "<" with " " for this publishing.
I'm using Eclipse and Jetty(Hosted mode).
Thanx a lot
andrash
Hi Chad,
I followed your instructions but I am getting a ClassCastException on java.lang.String on this line:
DataSource lDataSource = (DataSource) lContext.lookup("java:comp/env/jdbc/database");
I checked to see if the lookup was working with this
String str = (String) ctx.lookup( "java:comp/env/jdbc/database" );
and it returns "com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource@adecd4 "
Can you suggest what might be wrong with the DataSource lookup?
Thanks,
Don
Donald, what DataSource class are you importing? It should be javax.sql.DataSource. If it is I'll need more information in order to help. If it is can you post the code and stack trace to http://pastie.org/ or snipt.org or the like and leave the url I can take a look.
Ok, I've had some sleep and have looked at your post again and I believe the problem is with the way you configured the DataSource. Rather than registering the DataSource in JNDI the DataSource Classname is registered.
Are you running this in hosted mode in Jetty or on a different server. If you are running in Jetty what I would need to see is the jetty-web.xml file that you used to define your DataSource.
Hi Chad Skinner,
I still have the same problem with the mySQL-Connection.
All infos on http://pastie.org/706082
(eclipse, jetty in hosted mode)
Thanx a lot,
andrash
You will need to resolve the following error message:
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
I believe that this indicates that you have not setup the initial context system property to do this:
From the Menu Bar choose "Run" > "Run Configurations"
Verify that the correct Run Configuration is highlighted and select the "(x)= Arguments" tab.
Then under the VM Arguments section paste the line:
-Djava.naming.factory.initial=org.mortbay.naming.InitialContextFactory
Now I've get following error messages:
javax.naming.NoInitialContextException: Cannot instantiate class: org.mortbay.naming.InitialContext [Root exception is java.lang.ClassNotFoundException: org.mortbay.naming.InitialContext]
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
at javax.naming.InitialContext.init(Unknown Source)
the whole stack:
http://pastie.org/712434
The required Jetty jar files:
http://mirrors.ibiblio.org/pub/mirrors/maven2/org/mortbay/jetty/jetty-naming/6.1.12/jetty-naming-6.1.12.jar
http://mirrors.ibiblio.org/pub/mirrors/maven2/org/mortbay/jetty/jetty-plus/6.1.12/jetty-plus-6.1.12.jar
And if you need the mysql connector:
http://mirrors.ibiblio.org/pub/mirrors/maven2/mysql/mysql-connector-java/5.1.9/mysql-connector-java-5.1.9.jar
Chad, I figured out what was wrong with my jetty-xml. Apparently when I cut and pasted from your HTML example there were some whitespace characters that were preventing jetty from correctly parsing the xml. Once I replaced those characters with spaces it works great!!
THANKS for posting this solution!!!!!!!!
Don
To find out Jetty Version of GWT Plugin there is a pom.xml for jetty in gwt-dev.jar.
Score... this article saved my butt.
Thanks
Just in case anybody has trouble with this and uses ant and not eclipse, add the following line under the task under the "devmode" target:
(also make sure you have the aforementioned JARs in the classpath, of course)
Thank you for posting this!!!!
Does this example work with Google App Engine???
We do not use GAE in the School District where I work so I can not say for certain. However, It is my understanding that GAE does not support JDBC so you would have to use the APIs Google provides for Data Access or use JPA/JDO.
Hi,
M using jetty 7 and i am stuck with this error.
This is what i have in jetty.xml
jdbc/DBName
org.postgresql.Driver
jdbc:postgresql://localhost:5432/DBName
username
password
10
50
true
120
I have tried to put etty-plus-1.6.11.jar, and jetty-naming-1.6.11.jar in WAR_INF also. It dint work. please help
I don't see an error, nor is the jetty.xml valid xml ... post more information and I'll try to help.
Post a Comment