I have a JAVA webapp which is using DB connection pooling for Tomcat+MySQL config.
I have another JAVA webapp which i want to deploy in the same Tomcat and connect to same MySQL database (even access the data from same tables).
I havent figured out a way how to achieve the same.
Should I have connection pooling context.xml for each of the webapps?
Or should I have a global configuration.
In the first case , I assume there is nothing different that i need to do. Only to deploy the webapp which has its own context.xml.. Please correct me if i'm wrong.
If having a global config is a better solution, how to achieve that. Haven't found any good tutorials about it. What changes in each of webapps need to made , so that it knows that it needs to read the global config.
There's nothing wrong with having a separate context for each webapp unless you want to centrally manage changes to the database (i.e. migrate it to a different DB, change connection parameters). If you think your connection properties will change or you want that flexibility then you can use a JNDI datasource in tomcat and manage it there (google is your friend for that).
Related
We want to split a working application in two different .war files in order to be able to update one app without affecting the other. Each webapp will have different a UI, different users and different deploy schedule.
The easiest path seems to be sharing the same session, so if app A set session.setAttribute("foo", "bar") app B will be able to see it.
Is there a way to share the HttpSession state for both apps in the same Tomcat instance?
Our app is running on a dedicated Tomcat 5.5, there are no other apps running on the same tomcat instance, so any security concerns regarding the session sharing are not a problem. We're running multiple Tomcat instances, but the balancer is using sticky sessions.
If it's not possible or this session sharing is a really bad idea please leave a comment.
You should not share HttpSession; but you can share other objects. For example, you can register an object via JNDI and access the same object in all your apps (databases use this to pool connections).
One thing to be aware of is that two web apps will use different classloaders. If you want to share objects, they need to use the same version of the class from the same classloader (or else you will get LinkageErrors). That means either putting them in a classloader shared by both web apps (system classpath for example) OR using serialization to effectively drain and reconstitute the object in the right classloader with the correct version of the class.
If you want to use Spring, there's a project called Spring Session:
https://github.com/spring-projects/spring-session
Quoting: "HttpSession - allows replacing the HttpSession in an application container (i.e. Tomcat) neutral way"
For Tomcat 8 I use the following configuration to share a session across 2 webapps:
conf/context.xml
<Context sessionCookiePath="/">
<Valve className="org.apache.catalina.valves.PersistentValve"/>
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore" directory="${catalina.base}/temp/sessions"/>
</Manager>
...
</Context>
I deploy the same simple webapp twice log.war and log2.war:
/log
/log2
I can now log-in to /log and have the user displayed in /log2, this does not work with the tomcat default configuration.
The session value is set and read:
HttpSession session=request.getSession();
session.setAttribute("name",name);
HttpSession session=request.getSession(false);
String name=(String)session.getAttribute("name");
I used this project as example: https://www.javatpoint.com/servlet-http-session-login-and-logout-example
Most examples/solutions use a in-memory database which requires more setup work:
redis
hazelcast
If the two webapps are so closely coupled that they need to share objects, why are you splitting it in two? Even if you manage them somewhat independently any decent build management system should be able to create a single WAR file for deployment.
A solution like Aaron suggest with JNDI will work, but only if both webapps are running on the same server. If the units are tightly coupled and you are going to be running it on the same server anyway ... might as well have a single WAR.
If you really do want them to stand independently I'd seriously examine the data exchange between the two. Ideally you'd want them to only share relevant data with one another. This data could be passed back and forth via POST (or GET if more appropriate) parameters, you might even consider using cookies.
One way of doing this is described in this blog post: Session sharing in Apache Tomcat
Summary: Add emptySessionPath to the Connector configuration and crossContext to the Context
redison download
conf/context.xml
<Context sessionCookiePath="/">
...
<Manager className="org.redisson.tomcat.RedissonSessionManager"
configPath="${catalina.base}/conf/redisson.yaml"
readMode="REDIS" />
</Context>
conf/redisson.yaml
singleServerConfig:
address: "redis://<host>:6379"
sessionCookiePath="/" makes Tomcat use the same session id for different web apps.
RedissonSessionManager makes session to be persisted in 'shared space'
I was not able to achieve desired result with org.apache.catalina.session.FileStore PersistentManager in shared context.xml, I faced issues with session deserialization in background expiration monitor thread. It failed to deseriazile the session because it was using common classloader without webapp serializable models in classpath. Theoretically PersistentManager could be configured for each web app separately (to have proper classpath) in WEB-INF/context.xml but I failed to make it work.
org.apache.catalina.session.JDBCStore PersistentManage was promising because it expose last_access column for the session so it is not required to deserialize session_data, but it was saving app_name all the time causing same session id to be written as different rows for diffrent web apps. Thus session data was not stored in the shared place.
Spring Session has it`s own way to create session id. I was not able to find solution to force Spring Session to create same session id for different web apps.
Solution with core tomcat session id generation (with ability to generate the same for different web apps and RedissonSessionManager, which store data using session id as the only key and has it's own expiration mechanism) finally worked for me. The solution works perfectly with #SessionScope spring beans.
You can do by taking servlet context by your context root.
For retrieving variable.
request.getSession().getServletContext().getContext("/{applicationContextRoot}").getAttribute(variableName)
For setting variable:
request.getSession().getServletContext().getContext("/{applicationContextRoot}").setAttribute(variableName,variableValue)
Note: Both the applications should deployed in the same server.
Pls let me know if you find any problem
Tomcat 8 :
i had to do : <Context crossContext="true" sessionCookiePath="/"> in conf/context.xml
more details on config attributes here
and then to set the value(like #Qazi's answer):
ServletContext servletContext =request.getSession().getServletContext().getContext("contextPath")
servletContext.setAttribute(variableName,variableValue)
to get the value:
ServletContext servletContext =request.getSession().getServletContext().getContext("contextPath")
servletContext.getAttribute("user");
I developed session state server for tomcat using python.
Due to this I don't need to change the code already written for creating/accessing and destroying session. Also as there is separate server/service which is handling and storing session so not master cluster is needed. There is no session replication (as in tomcat clustering) in this case, rather this is session sharing between web farming.
You should not split your app that way in order by have high availability. You could deploy the whole app on many tomcat instances.
I have used MySqlDataSource for in jdbc connectivity.I have used following code
MysqlDataSource d = new MysqlDataSource();
d.setUser("user");
d.setPassword("pass");
d.setServerName("hostname.com");
d.setDatabaseName("db");
Connection c = d.getConnection();
Also i have searched there is an option of Configuring a MySQL Datasource in Apache Tomcat.
Is there any performance difference between these two? which one is best to use?
Configuring Datasource in tomcat will help you to share same data source between applications running in same tomcat. that Datasource will be managed by container (tomcat in your case).
while the Datasource created in code will be created by your application and can be used by that application only.
So if you have multiple application running on tomcat and accessing same data source, that configuring Datasource in tomcat will be good approach and have performance factor because only one data source is created and not having separate connections for each application
But if you have only single application that the first approach you have used is good one
They both use the internally the same driver, i dont think the performance is much different here, i guess if you need to access teh database only at that place and the enduser isn't supposed to use his own authentication you may use it directly from java, but if you will need the connectivity on different places it could be helpful to configure this using apache configuration, specially that if anything changes like database server, user name or whatever you don't need to get in the code to change it, this could be very important if end users have to set their own configurations.
The improvement of configuring a pool of Connections (as the one provided by tomcat) is mainly that you will actually create and close a lot less of connections.
When using a pool, when you request a Connection to a pool it will look if it has any connection already created and available for reuse and, if it has, it will provide you with it (instead of creating a new Connection, which is a heavy operation). You must still close() a Connection provided by Tomcat so Tomcat knows that it can now reuse when it is requested again.
Additionally, the advantage of the pool is that your code does not need to know the configuration data for the Connection. He just requests a Connection from a given pool and the sysadmin configures it, allowing for greater flexibility (the sysadmin does not need to know how to configure your app, just how to configure the Tomcat which is fairly more standard).
I want to be able to deploy my app using ANT to Tomcat.
I don't want the process to be any different for dev and prod. However the two use different databases i.e. myapp and myapp-dev
How can I make this happen? Can I store a variable in the different tomcat containers and make the application call the name of the database from Tomcat.
Or if what I am asking is ridiculous what is the generally accepted way to achieve deploying to dev and prod with the same process.
The generic way is to put the configuration string in a JNDI entry.
If JNDI is not a possible solution, then a property file in the right location (so it shows up in the classpath of the WAR files) is also useful, but needs careful documentation.
Have you considered letting the web container manage the database connection pool, so you only need a single one pr container, which then can be retrieved through JNDI?
I have some code that I want to make public. The code sends email via servers, connects to databases, and other tasks requiring usernames/passwords.
I'd like to store the passwords and such in a seperate configuration file so that I don't have to sanitize my code on every commit.
How can I do this? It would be easy to do in C using #define, but I'm not sure how to accomplish this in Java.
EDIT: The environment I'm using is Glassfish
The basic method is put the information in a properties file and use the Properties class to load it at run time. If you're using a J2EE server, database connections are configured in the server and the code references them by an abstract name.
I think I should add that if you're using a server, how to configure it and how to get the connections to your code will vary by server and J2EE level so post your environment. Using the Properties class is pretty obvious just by looking at the javadoc and the load() methods.
In glassfish, go to the admin console and under Resources create a new connection pool. That defines your database connection and will share a pool of those connections among your applications. Now under JDBC Resources, create a new entry that maps that pool to a name. The name is usually something like jdbc/myappname.
For a J2EE5 or later application, you can now add this as a class level variable:
#Resource(mappedName="jdbc/myappname") DataSource myDS;
At runtime the server will inject that resource to your database pool. Then when you need a connection, you can do this inside any method:
Connection conn = myDS.getConnection();
The result is your code doesn't have to care at all about the database connection information or managing a pool of connections. You can deploy the identical code on development and production servers, and they will get an appropriate connection. In order to get the injection, it has to be a class the server creates like an EJB, servlet, tag library handler, or JSF managed bean.
I have a set of EJBs and other Java classes which need to be configured differently based on the system environment in which they are deployed: production, test, or lab. The configuration information includes stuff like URLs and database connection information.
We'd like to deploy the same exact product (EAR file) in each environment, and have the code then figure out where it is and what its configuration should be, without having to reach out to each deployment server in each environment to make changes.
What is the best way to configure all these components in a centralized, reliable, easy-to-maintain fashion?
Thanks for your thoughts.
The best, IMHO, is to use JNDI entries.
You may have to recode some parts of your application in order to use theses entries instead of plain vars, but with this setup:
Configuration is server-independant: each vendor provides its own implementation, but spec is a standard.
In a clustered environment, config can be persisted in a cluster-wide JNDI tree (see JBoss)
Configuration can be changed thru webadmin without restarting server.
How database connection pool information is stored / configured depends on the app server vendor. Put other variable stuff in property files on the classpath.
If you are deploying the exact same EAR to three different instances of a certain container than you will have to edit the deployment settings as there is no way that the deployment process could have any idea about which one of your three versions you would like to use at a particular deployment.
Deployment settings should go into JNDI entries as Piere-Yves said above.
If I were you, I would have my deployment-script (Ant?) properly populate the JNDI entries depending upon which environment you are deploying to.