I have an EJB3 bean deployed as a web service in JBoss 4.2.2. In production the server is behind an Apache server that redirects requests to the Jboss server. This makes the WSDL have the wrong soap:address location. I was able to get the port and host name changed via the configuration file in server\default\deploy\jbossws.sar\jbossws.beans\META-INF, but I haven't been able to get it to switch the protocol to https.
The only way that I found was to specify my own WSDL (via here). By specifying https in the WSDL, JBoss picks up that it is https. However, although that is fine in production, in QA https is not used (and the service that connects to it requires valid https, so self-signed certificates won't do). So while I could get a real certificate for QA (fake certificate authorities won't do), I would rather have it be http in QA. Is there a way to force JBoss to change the protocol or otherwise change the address so that it uses http in the soap:address?
EDIT: It seems like this issue was brought up recently in their bug database and was rejected. That would imply to me that they have a work around. But what is it?
Further EDIT: At this point, I know that an EJB3 Interceptor doesn't work (they are not activated at all) and SOAPHandler's don't intercept the call to retrieve the WSDL (tested - they pick up everything else). So the filter idea is intriguing, but it is far from clear where to put it.
The URL as shown by JBoss is:
Endpoint Name jboss.ws:context=QuickBooks-QuickBooksWebService,endpoint=QBWSBeanEJB
Endpoint Address https://127.0.0.1:8443/QuickBooks-QuickBooksWebService/QBWSBeanEJB?wsdl
(Note that is when I use the custom WSDL to force https but JBoss is configured to rewrite it).
The version of JBossWS I'm using is what is bundled with 4.2.2, which according to this is 2.0.1
EDIT: With regards to the rewriting, this was indeed attempted. Here is what I found. I could get it to rewrite the host (or not as needed) and the port, but only for the recognized protocol. So in order to get it emit an https, I had to configure the bean's transport guarantee to CONFIDENTIAL, and enable https on the JBoss server, then all requests were redirected to https within JBoss. I didn't test if this would even work with mod_jk (does the AJP protocol still work if CONFIDENTIAL is required, and will the WSDL get the right protocol if the request comes over AJP? I didn't test it), however doing that has the same net effect - the requests must go over https. There is no way to have the request come in over http or AJP and then have it emit a soap:address as https, specifically configured on a per-server basis (in QA and dev, http, in but in production https even though the ssl was terminated by Apache). Using the custom WSDL got me closer, in that the request is coming in on HTTP, but the soap:address says https. Perfect for production (using the rewrite feature to push the port to 443 instead of 8443), but useless for QA (dev I don't care about, because the dev build could be different and create a different jar if needed, but I'm not comfortable with QA and production having different build processes if I can avoid it).
Why don't you set up a servlet filter on your web application which watches for WSDL requests and rewrites the soap:address in the responses using values from its configuration? Then you can set it up however you want.
It may not be the most elegant solution, I agree :-) - but then that would have been for the configurability to be in JBoss, wouldn't it? And if JBoss eventually introduces this feature, you can just remove the filter.
Update: A typical JBoss EAR has the following structure:
myapp.ear
|+ META-INF
|+ applications.xml and jboss-app.xml
|+ myapp.war
|+ web pages and JSP /JSF pages
|+ WEB-INF
|+ web.xml, jboss-web.xml, faces-config.xml etc.
|+ lib
|+ tag library JARs
|+ classes
|+ servlets and other classes used by web pages
|+ myapp.jar
|+ EJB3 bean classes
|+ META-INF
|+ ejb-jar.xml and persistence.xml
|+ lib
|+ Library JARs for the EAR
Can you confirm that your deployed EAR has this structure? If not, how is it different?
Update #2: JBoss automatically generates a web.xml for EJB3 beans which are in a JAR inside the EAR being deployed. This web.xml is definitely hard-coded (i.e. doesn't use as a basis an XML file which you can tweak) and so it is awkward (though not impossible) to change this to include a filter (you basically need to change various things in jboss-beans.xml to point to your own web.xml generator, which can do whatever you want). It would be a lot less development work if the EJB3 beans were in the WAR file - then you can configure the Filter conventionally using the WAR's web.xml, which you presumably have control over. However, that might be problematic if that's a third-party JAR you're using - or it might not. Without knowing the details it's hard to see which the best approach will be.
Edit from the question's author:
Thanks for all the effort. This appears to be the basic approach - intercept and change the WSDL. If you can't make your webservice a POJO assigned in the war, where you can use a servlet filter, then you can make a servlet that proxies the request, and do it that way. That was my solution.
We've faced similar issues in the past and decided that using SSL in all QA environments was desired (there are downsides - especially when debugging the HTTP streams - but what doesn't have downsides?)
This can be easier that you may think however since you seem to have control of all environments involved: you basically just need to tell Java that your self-signed certificates are "good". To do this you need to add yourself as a certificate authority in Java.
A good overview of the process is here:
http://en.wikibooks.org/wiki/WebObjects/Web_Services/How_to_Trust_Any_SSL_Certificate
Here's information from Sun about the KeyStore tool (although you should look for the reference specific to your version/JVM as there are differences):
http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/keytool.html
Once this is done your self-signed certs in QA will be 100% "valid" in Java.
You can even save some money sometimes in Prod: if you control both sides of the environment you can do self-issued certs in Prod and save some cash. Heck, if your user community is small/controlled enough you can add your self-signed authorities directly in client browsers as well (although that seems like it would be more trouble that its worth).
Hope this gets you moving in a useful direction!
Basically the only solution I found to this was to create a servlet which intercepts and proxies the WSDL request. I copied and implemented ProxyServlet from Apache's pivot project (it took some not-insubstantial changes, such as the Apache implementation only wrote responses to gets not posts). Basically the implementation checks if the request is a request for a WSDL, and changes the soap:address property in the WSDL. Hardly nice, but, it worked around that problem, but the whole thing is still not working because after we have communication, there is a further problem. Another question on SO I guess.
Related
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.
I am writing and small app using Java EE. I am using Apache Tomcat v 7 and Eclipse as IDE. When I Run the project (Run on server) I get :
http://127.0.0.1:8080/java-web/lis
(That's fine)
But I don't know If there is some way to rewrite the [java-web] dir just to get :
http://my-local-app.dev/list
I suppose there is some way like in Apache Server using confing files and enabling
the mod_rewrite.
I'll apreciate your help. Thanks
In short: All of the pieces you want to change are components of your deployment environment. Unless you have a specific need to override them, it's usually easiest during development to use the URLs that are a little less pretty.
If you do want to alter them, you need to familiarize yourself with what the various parts of an HTTP URL mean. What you have in your test environment is this:
http:// 127.0.0.1:8080/java-web/list
protocol host port path
You could insert an entry into your hosts file listing my-local-app.dev at 127.0.0.1, but that would not change the port or the path.
The port is determined when Tomcat starts up and is 8080 by default. The general port for HTTP is 80, but specific permission is required to bind to ports below 1024. On Linux, the authbind package makes this pretty easy; on Windows, the necessary steps will depend on your version and configuration (e.g., if you have a Group Policy).
In Tomcat, Web applications are prefixed with their names in the path; it looks like your (hypothetical?) application is named java-web.war. You can install an application as the "root application", but this requires a little bit more configuration and is generally skipped in development.
All of this can indeed also be done using something like mod_rewrite, but that seems like overkill to have slightly prettier URLs for your dev machine.
If you want your application to respond to the my-local-app.dev, you need to purchase the "my-local-app.dev" domain and get a Java web hotel running on it.
If your web application is named "java-web" and you do not want the URL to reflect that, you need to tell Tomcat that you want your application deployed at the ROOT location where the name of the web application is not present in the URL. This is typically done in the deployment stage but unfortunately there is no standard location to say this for WAR files so this is vendor dependent. For example does Glassfish use an extra XML file in your deployment.
I believe Tomcat supports this for ROOT.war files. If not, you probably needs to set the META-INF/context.xml file. See https://tomcat.apache.org/tomcat-7.0-doc/config/context.html for details on what to put in this file - especially the context path.
I have two webapps on one jetty server. Each has own domain, defined in jetty-web.xml, for example example1.com and example2.com. This is working fine. Now, if someone will point some other domain name(let it be example3.com) to my server, and tryed to access it by this name - server will not found context configuration for this new domain and will send default responce with list of installed apps. And I need to change this functionality - i want just hide list of my webapps. In documentation thay suggest use some webapp, named root. It is ok, but than i get conflict of names and this default webapp is overriding my applications, if it was deployed last. So my question is - how do i can change this default 404 page for hidding webapp list.
You need to prevent Jetty from showing context related information.
Hint: you can even write own implementation of DefaultHandler and inject in in same way as inbuilt is injected, as far as jetty.xml is IoC-style config.
After several days of searching, trying and head-banging, I post this question to SO although it seems to be answered already.
Here is the scenario:
I have an EAR application containing (for the moment) one WAR and one EJB module. The EJB module uses JPA (persistence.xml) and some Stateless Session Beans are exposed via Web Services. The web services use Basic authentication with a jdbc realm. The web module uses form authentication with the same realm.
The requirement:
I need to be able to deploy this application either on different servers (dev/test/prod) or on the same server (or cluster) with different deployment descriptors. The deployment settings that need to be different in each application instance are:
The jta-data-source in persistence.xml
The realm-name in web.xml
The javax.faces.PROJECT_STAGE in web.xml
The webservice-endpoint\endpoint-address-uri and login-config\realm in glassfish-ejb-jar.xml
The context-root in application.xml (i could move it to web.xml if it made any difference, see below)
The realm in glassfish-application.xml
During my research, I managed the following:
I can override the javax.faces.PROJECT_STAGE using asadmin set-web-context-param
I can override all settings in glassfish-ejb-jar.xml using a deployment plan during asadmin deploy
The same applies for glassfish-application.xml
I can probably override context-root during asadmin deploy (I don't know how would this work with more than one web modules in the EAR)
So far so good. This leaves me with the following problems:
How can I easily modify the the realm-name in web.xml?
How can I easily modify the jta-data-source in persistence.xml?
By easily I mean during deployment or using something similar to a deployment plan jar. Maintaining multiple copies of ejb.jar or war just with a modified .xml file is not an option.
Just to be clear, the need is to have different databases (either in different stages of development or for different customers) using the same application. The application uses one persistence-unit but it needs to point to different databases (hence the jta-data-source). The realm is a jdbc realm (on the same database) that also needs to be different per application instance.
Any help or pointer would be greatly appreciated.
Have you thought about preparing templates for the deployment descriptors, and populating them with value from property file during build? If you are using ant, you can use the expandproperties filter.
You can do all those things with a deployment plan jar.
It looks like the content of the deployment plan jar is pushed into archive/directory tree of the application BEFORE any of the heavy lifting associated with deployment happens.
See
http://java.net/projects/glassfish/sources/svn/content/trunk/main/appserver/deployment/javaee-core/src/main/java/org/glassfish/javaee/core/deployment/DolProvider.java
and
http://java.net/projects/glassfish/sources/svn/content/trunk/main/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/archivist/Archivist.java
Does the JSR 286 spec require the presence of a web.xml file in WARs containing portlets? At first, I thought so but then I created a portlet without a web.xml, deployed it in Liferay and it worked flawlessly. So is it an extension (or a bug) of Liferay, or is it not necessary to have such a file?
As Olaf rightly said portlet is nothing but a web application. Liferay has a listener that gets triggered when the portlet auto deploys. It explodes the war and adds web.xml and the content that is necessary. You can check the logic if you have source. The class name is PortletDeployer and the method is getServletContent. After add the web.xml and stuffing it, they just touch it using FileUtil.touch.
I'd really have to dig in the spec - but my assumption is that it's following the servlet spec in this regard: A portlet app is first and foremost deployed to an application server. If the servlet spec requires a web.xml to be there, this requirement would need to be fulfilled. Otherwise the Appserver would not deploy the WAR (it's more or less the question if the WAR file format requires or recommends web.xml
Liferay will only kick in once the Apperver has deployed a web application. Liferay itself doesn't care for web.xml
Based on this arguing (and without looking at the spec - so I'm giving an educated guess here) I expect JSR 286 to not make a statement about web.xml. However, it probably references the servlet spec and this in turn might require/recommend/mention web.xml.
And if the Appservers require it or how they behave if it's missing is yet another story.