This week's book giveaway is in the OCPJP forum. We're giving away four copies of OCA/OCP Java SE 7 Programmer I & II Study Guide and have Kathy Sierra & Bert Bates on-line! See this thread for details.
I am trying to figure out why I get two different session ids when I call two pages from the same web root. I thought I had declared the scope of each page properly, but the two pages will not "talk" to each other. I would appreciate anyone who can point me in the right direction for understanding what I'm doing wrong.
I'm working on code stored on a Tomcat 6 server with Java 6 on an Ubuntu server. Almost all the pages are written in JSP (including the two I'm working on). The web root's index.jsp has code to check if a session variable "netID" is set. If not, it prints out a splash/log in page. If "netID" is a field in the HttpSession object, the user gets the main page, which is also part of the code in <WEBAPPS>/index.jsp. This output is controlled by very large "if...else" statement.
I have this page printing the username from this session and the ID to Catalina.out for testing purposes. The page is set to session scope using a <%@page session="true" %> declaration, and also has a JavaBean which I believe is instantiating properly, as I can pass values in to it and call them out or call them without passing them in first.
There is another package, which has it's own login screen as this was absorbed from another department into our web schema. What was the web root of the second package was placed as a folder directly under the first package's web root, so that our schema is now:
This feeds from a MySQL database backend through JSP for the passwords and user data. Both contexts will pull from the database without issue, as this has been running for a little over two years now. I simply cannot get the session to be recognized in both locations. Instead, opening either page creates a session unique to that page, but:
Going to <WEBROOT>/index.jsp will give me a certain session ID (let's say ABC123), whereas going to <WEBROOT>/project2/index.jsp will give me a different session ID (XYZ789). If I refresh either page, I get the same ID. If I go back and forth, each page keeps it's own ID. If I:
1) go into <WEBROOT>/project2/index.jsp after restarting my server
2) load <WEBROOT>/index.jsp
3) open <WEBROOT>project2/index.jsp in a separate tab of the same window
I get project2's Session ID from step 1 showing up in step 3, which is what I would expect and proves that the server is finding Session IDs fine. I've checked my server's config files and found no instance of anything specifying separate Session IDs (although I only know enough from googling and checking other posts in here to make an attempt at verifying this, and claim no expertise).
My session declarations are as follows:
With bean declarations (currently removed) the code was:
<WEBROOT>/index.jsp called the setUser() method of admin103.userBean explicitly in the jsp code, passing it an object of type supportUser (an internal naming convention). I had originally planned to create a class userProfile and assign it to the session as an object, but that failed too due to the session IDs being different. I'm convinced I'm just not understanding some detail about how Session IDs are assigned. Could anyone point me in the right direction to figure out what I'm missing?
I'm afraid it's too early in the morning for me to actually read all that. In fact, I'd have to print it out in order to correlate that much info. So I'm going to take the easy way out.
Your query title says "2 contexts, one a subfolder of another". A Tomcat Context is a pairing of a root (context) URL with a WAR (plus optional injected configuration). A WAR cannot contain another WAR. WARs are supposed to be completely independent of each other. In fact, WARs are supposed to be completely self-contained. I wouldn't begin to try and predict what might go wrong otherwise, but if that's actually what you're attempting, I think you may be finding out. The hard way.
Customer surveys are for companies who didn't pay proper attention to begin with.
Joined: Jan 28, 2010
Perhaps I phrased this wrong. I'm referring to a context to denote two different processes on one server. Neither application is set up as a WAR file. The entirely of the suite is, in fact, exploded into a common file hierarchy. I know this is not the way Tomcat is expected to be used. The problem lies in the fact that I have one very large web suite which was designed by a former employee who sort of knew how to work with JSP and Tomcat. At the point after he left, I inherited his entire code base. We were then given another application/nested directory, which ran independently on one server in a different call center for the same company. This got installed as a sub-folder of our web root,. If we were to call the original suite Nostromo, we access <WEBROOT>/index.jsp by going to http://nostromo. Another call center in this company developed the application Sulaco, which is on their Tomcat install and accessed at http://sulaco. However, I was told we needed to have Sulaco work in my center, so what would be the root got installed at <WEBROOT>/sulaco. Now, we can access it through http://nostromo/sulaco, but get different session IDs. To my way of thinking (and if I'm misunderstanding, please correct me), the Tomcat server should see someone logged in to http://nostromo, then said person clicking on a link from the main page for http://nostromo/sulaco would qualify as accessing a page within the same context. Is this wrong? I understood it to be similar to me creating a sub-directory called <WEBROOT>/rotovator, with page rotovator/index.jsp, at which point I would expect that rotovator/index.jsp would pull the same session ID from the browser as nostromo/index.jsp would, since they're in the same context path. In fact, that's exactly how I have this set up, and both suites work together in all other aspects which I've had a chance to test, except session ID.
Is it possible I've just not found some definition (analogous to a symbolic link) in a conf file somewhere that tells Tomcat to treat /nostromo/sulaco as a separate context?
ALL webapps in tomcat are WARs. Even if it's not a "WAR file", the deployed webapp has to conform to the J2EE spec that defines what goes into a WAR and where. The difference is that if you UNZIP a WAR, you get what's known as an "exploded WAR". The structure is identical, since unzipping doesn't rearrange things, it just builds concrete directories and files out of the entries in the WAR file's directory. Even if you never zipped (jarred) the directories to begin with, you have to act like you had. J2EE doesn't actually recognize the concept of an exploded WAR - it's just a convenience offered by some servers such as Tomcat.
To be usable, every WAR has to have an associated context corresponding to its context URL, and you can list those contexts using the Tomcat management webapps. You referred to "processes". Webapps aren't processes. They're responders. From a strict point of view, a webapp is only active when a web client request is being processed. So what's important isn't the process (which doesn't exist), but the context. If a given incoming URL to the webapp server matches a given URL context path, then the URL is routed to that context's webapp.
If you just dump a WAR file or exploded WAR into the TOMCAT_HOME/webapps directory, a default context is created and its name/URL context path is the name of the root directory of that WAR. You can also create an explicit context with additional configuration and a URL context path of your choosing. However, ONLY the webapps directory is scanned. Subdirectories of WARs don't get given their own contexts. And, as I mentioned, WARs cannot contain other WARs, but must be completely self-contained. And they ESPECIALLY cannot share static objects, since each deployed WAR has its own unique classpath.
So, in short, a webapp cannot be subfolder of another webapp. It just doesn't work.
Joined: Jan 28, 2010
I really would like to thank you for taking the time to clarifying this, and I hope I'm not just being dense in trying to clarify my question. I understood part of what you mentioned when I had previously checked my server, but some of what you explained did clear a few other things up. I've looked through the deployment descriptor and all other xml files for a definition of sulaco anywhere, and only found it defined as a resource in <WEBROOT>conf/server.xml for the purpose of linking it to the sql driver and setting timeout. Would that be enough to qualify as defining a context?
Am I correct in assuming that if I define <WEBROOT>/index.jsp as a context, and make no definitions whatsoever of <WEBROOT>/subdir as a separate context, then <WEBROOT>/subdir/index.jsp should be able to access the same session ID using httpSession? This is how I have the pages set up, since I had to take part of a full online application and add it's functionality into our app. However, as I understand your explanation, the fact of having a folder with an index.jsp file as a sub-dir will even be picked up as a separate context for the purpose of creating a default context. So, if I take my main app's (Nostromo) exploded WAR and code an index.jsp file in a new subfolder (Betty), shouldn't the session object called in a link from http://Nostromo/index.jsp to http://Nostromo/Betty/index.jsp get the same session ID?
I apologize if I'm not getting something here.
Well, let me make sure we're both talking about the same thing when you say <WEBROOT>
A WAR has a root directory under which all the other resources are stored. So if I deploy "myapp.war" and don't define a custom context, Tomcat will by default explode "myapp.war" as a directory named "myapp" in the TOMCAT_HOME/webapps directory. A Context refers to the root of the webapp. So the URL base context for the WAR I mentioned will be "http://myserver:8080/myapp" and the index.jsp in the WAR root will have a URL of "http://myserver:8080/myapp/index.jsp". The URL isn't the context, however, the context is only portion of the URL path that the webapp was deployed under (which is simply "myapp"). Thus, /myapp/index.jsp, /myapp/servlet1, myapp/css/style.css are all components of the /myapp URL context. You could define an explicit context where myapp.war was deployed under the context name "yourapp", and the URLs would then change to "/yourapp/index.jsp", "/yourapp/servlet1" and so forth, since the actual name of the WAR is NOT part of the context nor of the WAR resource path.
If you're using <WEBROOT> to mean "TOMCAT_HOME", I should caution that defining Context elements in TOMCAT_HOME/conf/server.xml has been discouraged for a long time now. There are better places to define Context XML elements.
And TOMCAT_HOME/index.jsp or TOMCAT_HOME/subdir could only be used as web resources if you'd really mis-defined some things to the point that you'd created major security exposures in the server. Under normal/default conditions, these locations are completely outside of any webapp and thus cannot be accessed by any URL.
Let's assume that you deploy 3 directories under TOMCAT_HOME/webapps: app1, app2, app3.
TOMCAT_HOME/webapps/app1 will be deployed by default under the context name /app1
TOMCAT_HOME/webapps/app2 will be deployed by default under the context name /app2
TOMCAT_HOME/webapps/app3 will be deployed by default under the context name /app3
And a TOMCAT_HOME/webapps/app1/app4 will NEVER deploy under any context. It will instead be seen as a resource within the /app1 context.
So http://myserver:8080/app2 will reference resources under the TOMCAT_HOME/webapps/app2 directory. app2 cannot see anything in app1 or app3. The same applies to app1 and app3 relative to app2. A webapp can only see resources within itself.
Likewise, an HttpSession object created for a user of app1 is not shared with app2 or app3 and vice versa. Unless you configure TOMCAT for shared sessions. But that's a whole different topic.
Don't feel bad about being confused. I'm not following you as well as I should. I'm mostly just trying to help you get your terminology straight and help you understand what parts go in what places and how they interact.
Joined: Jan 28, 2010
Right, the part about apps1-3 not seeing each other I was aware of. I had checked all the conf files in TOMCAT_HOME/conf/server.xml because I have found config settings in the past which were "good enough" for a temporary workaround on this project's nascent stages, but were never fixed or updated. The last programmer and I had different styles of programming, to the point where he'd only read documentation until he found something that worked for him, then forget to see if there's a better way of doing something. So, I occasionally get bit in the kiester by something he did a while back, because there was a "lone gunslinger" mentality with the development teams in all the call centers that left me no end of grief. I know we haven't started tinkering with explicit contexts for defining alternate URLS since that guy left, and so far nothing has been defined in the universal config files, but I wanted to check those to be thorough.
When I say <WEBROOT>, I'm referring to <TOMCAT_HOME>/webapps/ROOT, which is where our main app is deployed. I guess the better way I could have described this is that we took the app from a different department, and only put enough of it in to be a resource of the first app. As it stands, we have 30-40 resources of our root app, all accessed via ajax, with our root app functioning as the web portal and handling log-ins, sessions, and employee identification.
I guess the best way to phrase my question would be: Under normal circumstances, should all resources in the same context get the same session ID number from httpSession?
Also, does the first volume of [i]Core Servlets and Java Server Pages [/i] by Marty Hall cover all this in detail? I'm going to try and get through it during the winter session, using a clean install on my home Ubuntu box so I can get used to working with Servlets and configuring Tomcat.
The resource inter-visibility is predicated more on the URL context than the directory structure. Use of the ROOT folder to hold the webapp doesn't really make any difference. It's simply the context whose path is "/" and an "/app1" context is a completely different context regardless of where its directories are.
Contexts are based on the entirety of the context URL and don't form sub-contexts. The longest context that matches a URL determines which webapp the URL is routed to. Unless someone would care to correct me.
Don't depend on an user's session ID remaining invariant throughout the session. I don't think the spec guarantees that, and I definitely won't guarantee it won't up and change in the middle of things without warning without formal docs stating otherwise. The session ID doesn't really belong to you and it's best to leave its creation and use to the container - among other things, don't manually attach it to a URL, use the urlRewrite methods, as they can be expected to be more in touch with the server's internals.
What really counts, of course, isn't the session ID. It's the HttpSession itself. As long as you stick to the spec, regardless of the session ID, you'll always see the same HttpSession for the same user for the same webapp context. Until it's destroyed and a new one created, such as by logout/login or session timeout.
But it's very questionable practice to attach a webapp context to a directory that's under a directory for another webapp context. Even ROOT and "ordinary" webapps are both at the same directory level in TOMCAT_HOME/webapps. If there's any doubt, extract the offending subdirectories and make a brand new WAR out of them.
Incidentally, it's OK to take the samedirectory (WAR) and deploy it under more than one context. But the classpath rules are less ambiguous in a case like that.
Joined: Jan 28, 2010
I'm glad you pointed that out about the session possibly changing mid-session, but that would be fine. All the user would experience in that case would be one of the links asking him/her to log back in. I'd like your advice on something, however.
After your explanation, I set up a test server which mirrors our current codebase. using this guide, I've got the session ID coming up the same from the two contexts we use. More importantly, logging onto the site from any other computer gives a different session ID, which is accessed by both contexts. I tried having two people interact with the site simultaneously, and didn't notice any issues with both computers getting each other's data. It looks like I've now got the two contexts sharing the Session ID, which is IP specific. If you have experience with setting this up, could you tell me if there's anything you notice which I've overlooked in terms of securely using this technique?
If you're sharing the same session ID - which is nothing more than the handle that locates the server-side HttpSession information for that client - then that's not a problem as long as all the code plays nice. My concern was always more for the possibilty of class data corruption if 2 different apps were attempting to share the same class at the same time. That's because normally, each webapps would be using its own classloader.
The reverse problem is also a concern. If one webapp updated a class variable and the class had been loaded under Context A's classloader and another class expected to see that change but was running under Context B's classloader, I think it would be disappointed.
Joined: Jan 28, 2010
Makes sense. Thankfully, nothing in either context uses the same class, as these are all internal business models developed mainly for SQL interaction, so there's no spots where the same class can be duplicated. The session Id will just be used to authenticate that the user is passing over the correct credentials.
Thank you for going through the explanations you've posted. This helped me immensely.