Java - Managing Context Path - java

I have been working on an application that is currently being to deployed to numerous environments. However, we are having issues with the context path when deployed to certain environments. This is a Java/Spring application running on Tomcat 6. The deployment process is handled by system administrators so I don't have much visibility into the process so I'm trying to come up with some ways of handling the scenario. With all URLS, we prepend them with request.getContextPath(). Under normal circumstances, this works fine. For example, if WAR has the filename site1.war, it gets deployed to
/site1/
However, we have a couple of other environments where the WAR is deployed and it contains a rootpath outside of the application root so it ends up with
/otherroot/site1/
So the application root path is /site1/ and is unaware of this other rootpath /otherroot/. In this case, calling getContextPath() returns /site1/ when in reality the path that we want is /otherroot/site1/.
Now, one thing that has me confused is that when we use #{request.contextpath} within a JSF page when defining images (images, stylesheets or javascript files), the URL is correct when looking at the source. For example, given the /otherroot/site/ url, if I set
<img src="#{request.contextPath}/image1.png"/>, when I look at the source of the rendered page, I see /otherroot/site1/image1.png. Now, if I set some JS variable to hold the context path every time the page is rendered, I get a different result. For example,
<script>
APP.ROOT_PATH = '#{request.contextPath}';
</script>
This renders the following:
APP.ROOT_PATH = '/site1'
This is causing some issues because we make use of asynchronous requests so we use the url to properly request data from the client side.
So my question is, what is the best strategy for writing an application that can run under any given path?

You can achieve this by using interceptors which would identify the environment for you. You can pass the environment path through model to UI which could be used by UI.
For eg. /otherroot/site1/ , in this site1 is the context name and otherrrot is the environment.
When yo hit your server to render a jsp, interceptor will analyze this url and come to know that url has something to do with otherroot1. This environemnt and related data can be set in model which could be used to fetch js, images etc and for any other ajax call.
No need to rely on url context path once page is rendered.

Related

Liferay getting URL params issue

I have a page in which I have deployed a portlet, in my portlet I access some params using the url in the browser like:
localhost.com:8080/mypage?text=helloworld
with using
PortalUtil.getOriginalServletRequest(request).getParameter("text")
and it is working fine.
The issue comes when there is some latency in view.jsp rendering (like putting some debugger in Java code) and in the meanwhile the render portlet view.jsp is called again but this time I cannot read the "text" param from request
From client side the url being called is as follows:
> http://localhost:8080/c/portal/render_portlet?p_l_id=92438&p_p_id=editor_WAR_heliumportlet&p_p_lifecycle=0&p_t_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=column-1&p_p_col_pos=0&p_p_col_count=2&p_p_isolated=1&currentURL=
> ...
This url doesn't contain my param, I can't find a clue from where this url is triggered. Any help would be greatly appreciated.
Liferay can push portlets to be rendered asynchronously if they take too long to load (e.g. when attached to a debugger). This is due to the default values for render-weight and ajaxable, which allow this. Change them in liferay-portlet.xml.
Also note that fetching generic HTTP parameters that are not namespaced is not part of the spec, that's why Liferay doesn't care to forward the non-namespaced-parameter from the original URL to your portlet when it rendered it via AJAX. In other words: By using this technique you're probably preparing yourself for quite some more trouble in future.
As far as portlets can share the same page with other portlets, portlets use to have a prefix or a namespace.
This namespace can be always the same for a given portlet if this portlet is not instanceable. Or this namespace ca be variable with the purpose of being unique for each instance of the portlet.
So, the parameters for a portlet must be prefixed with the namespace.
Then, it will be easy to access this param using util tools like..
ParamUtil.get(renderRequest, "paramName", "defValue");
Here the java doc
https://docs.liferay.com/portal/6.2/javadocs-all/com/liferay/portal/kernel/util/ParamUtil.html
Regards

Can I have multiple Java webapps with overlapping paths?

I have a large collection of different independent (stateless) web services written in Java and compiled as WAR files. I want to deploy them to a single web application server.
If the URIs handled by the services in each WAR file began with a prefix I could use as a web app name, then this would be easy. I could, for instance, have
SALES WAR FILE: contains code for the following:
GET http://example.com/sales/widgets
POST http://example.com/sales/widgets
GET http://example.com/sales/sky-hooks
MARKETING WAR FILE: contains code for the following:
GET http://example.com/marketing/widgets
PUT http://example.com/marketing/sky-hooks
...in which case I would simply deploy two WAR files under the names "sales" and "marketing". However, I am not that fortunate. Instead, the URI paths handled by the components overlap. Something like this:
SALES WAR FILE: contains code for the following:
GET http://example.com/widgets/sales
POST http://example.com/widgets/sales
GET http://example.com/sky-hooks/sales
MARKETING WAR FILE: contains code for the following:
GET http://example.com/widgets/marketing
PUT http://example.com/sky-hooks/marketing
My question is how (if at all) I can deploy these on a single web application server.
I am open to suggestions that require a significant amount of work. For instance, my best-so-far idea is to build services that expect a component-name prefix before the regular URI path, then pipe all incoming traffic through a different server that knows what component each URI pattern falls into and modifies the URI to add that prefix. The difficulty with this approach is that tools like Swagger that read my source code will have a mistaken idea of what the URIs look like.
Any ideas?
If you're willing to put apache in front of your web container, you can use apache's mod_proxy to forward request to the right place.
One way this could work, would be deploy the separate wars at separate prefixes as in your first case (sales and marketing) and then use ProxyPass to send the requests to the correct place:
ProxyPass /widget/sales http://example.com/sales/widget
ProxyPass /sky-hooks/sales http://example.com/sales/sky-hooks
ProxyPass /widget/marketing http://example.com/marketing/widget
ProxyPass /sky-hooks/marketing http://example.com/marketing/sky-hooks
Its probably a better idea to just refactor your routing though - it might be hard to maintain.
(EDIT: I originally suggested mod_rewrite, but I wanted to make my answer more specific, and it looks like this could be done purely with proxying)
If I understand your question correctly, one of the solutions would be (I am assuming Tomcat is used but this should apply to most of the modern servlet containers):
1) Deploy your sales and marketing wars with different prefixes. I.e., using your example, they should be able to serve the following urls:
GET http://example.com/sales/widgets/sales
POST http://example.com/sales/widgets/sales
GET http://example.com/sales/sky-hooks/sales
GET http://example.com/marketing/widgets/marketing
PUT http://example.com/marketing/sky-hooks/marketing
2) Use UrlRewriteFilter to craft lightweight web application that will be deployed to your servlet container root prefix (for Tomcat it is called ROOT.war) and will rewrite urls in incoming requests to point to relevant web application.
In other words, incoming request like:
/widgets/sales
will be transformed to:
/sales/widgets/sales
... and delivered to sales webapp.
Similarly, in response urls like:
/sales/widgets/sales
will be rewritten to:
/widgets/sales
3) Deploy this war to root of your servlet container.
This approach is somewhat similar to the one suggested by #nont but does not require apache as a frontend as the rewriting functionality will be handled by root web application (UrlRewriteFilter basically implements mod_rewrite functionality).
In other words you'll be able to deploy all your applications (including this rewrite application that is deployed to the root prefix) to single server alleviating need for extra intermediate proxy/rewrite servers.
First, Determine How the Deployments may be Configured
Are you sure the absolute URIs must overlap? The context root will prefix the path supported by each service, unless the absolute path has somehow been coded into the application itself. The first step is to enable direct access to each WAR file, either through unique context roots or application instances.
Option 1: Set the Context Root for each WAR File Explicitly
The context root for a war file is set at deploy time. For some servers, this can be set outside of the web application using an external deployment descriptor. For Tomcat, it may embedded within META-INF/context.xml. See http://tomcat.apache.org/tomcat-7.0-doc/config/context.html for more information.
Option 2: Separate the Context Root Instances using Multiple Containers
Alternatively, deploy each war file to a separate instance of a Java EE servlet container, each running on a different port. This will solve the deployment conflict in the case of a hard-coded absolute path.
Finally, Set up a Virtual Host and Proxy the Requests via Apache and mod_jk
Once the context roots instances have been made uniquely accessible by one of the previous methods, configure an instance of Apache to serve as a reverse-proxy. First, set up a virtual host to handle requests for the externally visible URI. Next, configure mod_jk to route the requests to the correct WAR file deployment. See http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html for more details.
Afterthoughts
The above solution approach is generic for this type of problem and will require some knowledge of Apache and Tomcat configuration, which were chosen as example reverse-proxy and Java EE servlet technologies for its implementation. Additional detail on the deployment constraints would help to determine an optimal solution. In general, identifying the hard constraints on what may be changed versus what may not be changed should guide you quickly to a solution.
The obvious slotuion is to rename the wars, or refactor so that the appropriate mappings are in the correct place.
Anything else is going to be a bit hacky, you can't change the war name, even to soemthing like below :
SALES WAR FILE: contains code for the following:
GET http://example.com/webapp1/widgets/sales
POST http://example.com/webapp1/widgets/sales
GET http://example.com/webapp1/sky-hooks/sales
MARKETING WAR FILE: contains code for the following:
GET http://example.com/webapp2/widgets/marketing
PUT http://example.com/webapp2/sky-hooks/marketing
You could also create another war for routing/filtering, that redirects everything appropriately - but that also relies on altering url somewhat.
This is a use case for Reverse Proxy. If your web server is Apache, as suggested by #nont proxy_mod can be used to create a reverse proxy.
I know that IBM Http Server (IHS) also allows this mod.

Faces Servlet Application URL JSF/Glassfish

So I have let's say an application named MyApplication. I deploy it with a virtual server on glassfish and all is well since I set the default welcome page. Let's say the virtual server is to listen on mydomain.com
I goto mydomain.com and i see my index file of my application just fine. Then i go to do a j_security_check login.
And i am then redirected to: http://mydomain.com/MyApplication/page.xhtml
How can I get this to wehre it is: http://mydomain.com/page.xhtml ?
Now if I do take MyApplication out of the URL and try to manually goto that page it is blank, as I believe it is not being processed by JSF.
What I have tried.
* Setting the default glassfish application to my application and setting the context path of my application to / (glassfish complains and i cannot deploy my application)
* Doing the same as above without setting my context path to / and leaving it as is.
Will deploy but same issue.
My main reason for wanting this, is it seems if someone does get redirected to a path without the application name, the session state appears to be different. And causes some sporadic issues with session collision and values not being passed properly. So I either want to force the URLS to use the ApplicationName all the time, OR force them to not use it for the sake of consistancy.
There should be a way to accomplish this since I dont believe we should always have to have the ApplicationName in the URL.
Please help if you can, what I have found by searching seems to take care of it for the initial request but not when doing redirects using the FacesContext extenralContext redirect.
Unless I am not redirecting properly. I am at a loss here.
Thank you for the help.
IMHO you should consider using asap PrettyFaces
Your application URLs will always be elegantly displayed to your users.

Remap image requests in a web application (tomcat) with spring for an absolute path

i'm trying to find a way remap a path to an absolute one in order to retrieve images stored in the server filesystem, i'm also using spring mvc but the <mvc:resource> can't map absolute paths, and i can't find a nice way to do this with spring controllers
i.e. I need to map all the image requests from /images/** to /root/var/img/**, in this way when a client browser try to load an image of the page, every images stays in the path above mentioned
You can create a new context with docBase referencing to your folder (/root/var/img) It should look like this:
<Context path=”/images” docBase=”/root/var/img/” ... >
</Context>
Refer to Tomcat context configuration documentation for more details (e.g., for Tomcat 6: Apache Tomcat Configuration Reference: The Context Container).
Introduction to this document lists possible places where context elements can be defined.
EDIT
As I mentioned in comments, Spring-specific way to do this without creating any new context seems to be using RedirectView (link to Spring v2.5 JavaDoc). According to JavaDoc:
"View that redirects to an absolute, context relative, or current
request relative URL, by default exposing all model attributes as HTTP
query parameters."
EDIT2
It seems I've misunderstood RedirectView purpose, which is a good old URL redirection. Thus, answer by #Jens should be more appropriate (+1). I still wonder if there's an existing standard solution in Spring (what I originally thought RedirectView would do..) It's not like there's much code to write, but still :)
EDIT3
After reading more on this topic, I found out that <mvc:resources> is able to do this (i.e., mapping resource using not only relative path, or classpath), you just need to correctly configure location using file: prefix . In fact, there's already answer on SO that explains exactly what you need to do: Spring : serving static resources outside context root
not sure if I am getting that right but I think the common way to do that is to set up a controller which is mapped on the requests to /images/:
#RequestMapping(value ="/images/")
public void fetchImage(#RequestParam String id, HttpServletResponse response)
Then the controller can load the requested image from a configured directory like "/root/var/img" and write it the the OutputStream of the response. E.g:
org.apache.commons.io.IOUtils.copy(fileInputStram, response.getOutputStream())
In addition you have to set the correct mime type etc. in the response.
Jens

How to store a file on a server(web container) through a Java EE web application?

I have developed a Java EE web application. This application allows a user to upload a file with the help of a browser. Once the user has uploaded his file, this application first stores the uploaded file on the server (on which it is running) and then processes it.
At present, I am storing the file on the server as follows:
try {
// formFile represents the uploaded file
FormFile formFile = programForm.getTheFile();
String path = getServlet().getServletContext().getRealPath("") + "/"
+ formFile.getFileName();
System.out.println(path);
file = new File(path);
outputStream = new FileOutputStream(file);
outputStream.write(formFile.getFileData());
}
where, the formFile represents the uploaded file.
Now, the problem is that it is running fine on some servers but on some servers the getServlet().getServletContext().getRealPath("") is returning null so the final path that I am getting is null/filename and the file doesn't store on the server.
When I checked the API for ServletContext.getRealPath() method, I found the following:
public java.lang.String getRealPath(java.lang.String path)
Returns a String containing the real path for a given virtual path. For example, the path "/index.html" returns the absolute file path on the server's filesystem would be served by a request for "http://host/contextPath/index.html", where contextPath is the context path of this ServletContext.
The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators. This method returns null if the servlet container cannot translate the virtual path to a real path for any reason (such as when the content is being made available from a .war archive).
So, Is there any other way by which I can store files on those servers also which is returning null for getServlet().getServletContext().getRealPath("")
By spec, the only "real" path you are guaranteed to get form a servlet container is a temp directory.
You can get that via the ServletContext.gerAttribute("javax.servlet.context.tempdir"). However, these files are not visible to the web context (i.e. you can not publish a simple URL to deliver those files), and the files are not guaranteed in any way to survive a web app or server restart.
If you simply need a place to store a working file for a short time, then this will work fine for you.
If you really need a directory, you can make it a configuration parameter (either an environment variable, a Java property (i.e. java -Dyour.file.here=/tmp/files ...), a context parameter set in the web.xml, a configuration parameter stored in your database via a web form, etc.). Then it's up to the deployer to set up this directory for you.
However, if you need to actually later serve up that file, you will either need a container specific mechanism to "mount" external directories in to your web app (Glassfish as "alternate doc roots", others have similar concepts), or you will need to write a servlet/filter to serve up file store outside of your web app. This FileServlet is quite complete, and as you can see, creating your own, while not difficult, isn't trivial to do it right.
Edit:
The basic gist is the same, but rather than using "getRealPath", simply use "getInitParameter".
So:
String filePath = getServletContext().getInitParameter("storedFilePath") + "/" + fileName;
And be on your way.
Edit again:
As for the contents of the path, I'd give it an absolute path. Otherwise, you would need to KNOW where the app server sets its default path to during exeuction, and each app server may well use different directories. For example, I believe the working directory for Glassfish is the config directory of the running domain. Not a particularly obvious choice.
So, use an absolute path, most definitely. That way you KNOW where the files will go, and you can control the access permissions at the OS level for that directory, if that's necessary.
Writing to the file system from a Java EE container is not really recommended, especially if you need to process the written data:
it is not transactional
it harms the portability (what if you are in a clustered environment)
it requires to setup external parameters for the target location
If this is an option, I would store the files in database or use a JCR repository (like Jackrabbit).

Categories

Resources