Success! UriInfo is now using the HTTP request info, both through HTTP and AJP. I've confirmed with apache-tomee-1.5.2-20130208.041201-63-jaxrs. Absolutely no configuration changes were needed, either. I unpacked the snapshot, copied the test app to webapps/, ran bin/startup.sh, and tested.
This is exactly the behavior I'd expected initially, and should allow JAX-RS UriInfo to work through HTTP and AJP load balancers on TomEE. Thank you! -- Chet On Feb 7, 2013, at 9:08 AM, Romain Manni-Bucau <[email protected]> wrote: > oh think i misunderstood, in fact you want the input value so potentially > the load balancer value, not always the ajp info right? > > so i hope my fix will help > > *Romain Manni-Bucau* > *Twitter: @rmannibucau <https://twitter.com/rmannibucau>* > *Blog: **http://rmannibucau.wordpress.com/*<http://rmannibucau.wordpress.com/> > *LinkedIn: **http://fr.linkedin.com/in/rmannibucau* > *Github: https://github.com/rmannibucau* > > > > 2013/2/7 Chet Hosey <[email protected]> > >> AJP isn't generally exposed to the client at all. >> >> A typical configuration might include a web server such httpd or IIS >> listening on a public IP on port 80, and several Tomcat instances running >> AJP on private IP addresses. The web server is configured to route certain >> requests (like /appname/*) to a running Tomcat instance via AJP. If >> sessions are clustered, or the conversations are stateless, an >> administrator shut down an individual Tomcat instance without impacting >> external users. >> >> So a REST request would be made over HTTP (or HTTPS) to the web server, >> and routed to one of the Tomcat instances over AJP. There's nothing special >> about REST that makes AJP inappropriate; it's just a way of connecting a >> web server to Tomcat. But please consider an HTTP load balancer running on >> port 80, and sending requests to internal Tomcat instances running on ports >> 8080, 8081, etc. The client will send requests to port 80. But none of >> Tomcat servers' connectors will be bound to the same port. It would similar >> to AJP, in that the public port doesn't match the Tomcat connectors' listen >> ports. And all communication would be over HTTP. >> >> Even with requests over AJP, for example, a REST method can get an >> injected HttpServletRequest object. My test code demonstrates that. This is >> why I believe that the right behavior for UriInfo would be to match the >> behavior of the HttpServletRequest object. It generally works >> out-of-the-box, and there are already ways for an administrator to override >> the values returned by HttpServletRequest without having to alter the >> application. >> >> I'll try the latest snapshot, and put the AJP connector first as you >> advise. Please consider, though, that the correct public host / port may >> never match a connector's configuration, and that it may be better for >> UriInfo to get these values from an HttpServletRequest than to check the >> connectors. >> >> Thanks! >> >> On Feb 7, 2013, at 8:14 AM, Romain Manni-Bucau <[email protected]> >> wrote: >> >>> updated as possible as it was this feature >>> >>> can you try with the next snapshot please? >>> >>> where i doubt is when using ajp protocol you don't really respect REST >>> specification which relies on http only. >>> >>> *Romain Manni-Bucau* >>> *Twitter: @rmannibucau <https://twitter.com/rmannibucau>* >>> *Blog: **http://rmannibucau.wordpress.com/*< >> http://rmannibucau.wordpress.com/> >>> *LinkedIn: **http://fr.linkedin.com/in/rmannibucau* >>> *Github: https://github.com/rmannibucau* >>> >>> >>> >>> 2013/2/7 Romain Manni-Bucau <[email protected]> >>> >>>> Hmm, the point is it needs to select the connector to use for deployment >>>> (to compute the base address)...not sure of a clever way here >>>> >>>> Can you try to define ajp connector first in server.xml please? >>>> Le 7 févr. 2013 08:24, "Chet Hosey" <[email protected]> a écrit : >>>> >>>> To say that it's "deployed on HTTP" is inaccurate. It's deployed on >>>>> Tomcat, which TomEE is built around, and which provides more than one >> type >>>>> of connector. >>>>> >>>>> It's common to use httpd in front of Tomcat to serve static content, >>>>> balance between multiple workers, etc. It's reasonable that AJP support >>>>> might not be ready yet or might have been overlooked. >>>>> >>>>> The statements on the project's website suggest that the goal is to add >>>>> features to Tomcat without sacrificing functionality: >>>>> >>>>> - Goal: "Simple, Get more from Tomcat without giving anything up." >>>>> - Focuses: "Don't mess with Tomcat" >>>>> - TomEE doesn't "include Tomcat in some truncated and stripped-down >> form" >>>>> - With TomEE, there's "no picking and choosing individual parts of >> Tomcat >>>>> and building a 'new' server leveraging Tomcat." >>>>> >>>>> With such strong language, it would be surprising if the project didn't >>>>> plan to support AJP connections as it does HTTP. >>>>> >>>>> Might this be addressed in a future release? Can you suggest ways to >>>>> contribute? >>>>> >>>>> >>>>> On Feb 6, 2013, at 5:40 PM, Romain Manni-Bucau <[email protected]> >>>>> wrote: >>>>> >>>>>> because the REST service is deployed on HTTP not AJP >>>>>> >>>>>> *Romain Manni-Bucau* >>>>>> *Twitter: @rmannibucau <https://twitter.com/rmannibucau>* >>>>>> *Blog: **http://rmannibucau.wordpress.com/*< >>>>> http://rmannibucau.wordpress.com/> >>>>>> *LinkedIn: **http://fr.linkedin.com/in/rmannibucau* >>>>>> *Github: https://github.com/rmannibucau* >>>>>> >>>>>> >>>>>> >>>>>> 2013/2/6 Chet Hosey <[email protected]> >>>>>> >>>>>>> >>>>>>> That was my expectation too. But it just isn't working that way for >> me >>>>>>> with AJP. >>>>>>> >>>>>>> Apache httpd is listening on port 8888 and forwarding application >>>>> requests >>>>>>> (/rs-test/*) to TomEE via AJP. TomEE is listening on ports 8080 for >>>>> HTTP >>>>>>> and 8009 for AJP requests. If the UriInfo matched the request info, >>>>> then >>>>>>> the port number given should be 8080 when loading an app from TomEE >>>>>>> directly, and 8888 when using httpd to load the app via AJP. >>>>>>> >>>>>>> When I request http://servername:8080/rs-**test/< >>>>> http://servername:8080/rs-test/>to get content directly from TomEE via >>>>> HTTP, the UriInfo methods match the >>>>>>> request info, which also matches the server.xml host name and HTTP >>>>>>> connector port (8080). But when I request >> http://servername:8888/rs-** >>>>>>> test/ <http://servername:8888/rs-test/> to get content from TomEE >> over >>>>>>> AJP, UriInfo still lists the HTTP connector port (8080) instead of >> the >>>>>>> request port (8888). The HttpServletRequest and HttpHeaders objects >> do >>>>>>> return the request port, but UriInfo does not. >>>>>>> >>>>>>> What I tried: >>>>>>> >>>>>>> 1. Set up the environment >>>>>>> 1. export TESTDIR=/tmp/test >>>>>>> 2. mkdir -p $TESTDIR >>>>>>> 3. export JDK_HOME=/opt/java/jdk1.7.0_11 >>>>>>> 4. export PATH=$JDK_HOME/bin:$PATH >>>>>>> 2. Download, build, and install Apache httpd >>>>>>> 1. Download and unpack httpd-2.2.23.tar.bz2 >>>>>>> 2. cd httpd-2.2.23 >>>>>>> 3. ./configure --prefix=$TESTDIR/httpd >>>>>>> 4. make && make install >>>>>>> 3. Download, build, and install mod_jk >>>>>>> 1. Download and unpack tomcat-connectors-1.2.37-src.**tar.gz >>>>>>> 2. cd tomcat-connectors-1.2.37-src/**native >>>>>>> 3. ./configure --with-apxs=$TESTDIR/httpd/**bin/apxs >>>>>>> 4. make && cp apache-2.0/mod_jk.so $TESTDIR/httpd/modules/ >>>>>>> 4. Download and unpack apache-tomee-1.5.1-jaxrs.tar.**gz >>>>>>> 5. Configure Apache httpd >>>>>>> 1. Edit $TESTDIR/httpd/conf/httpd.conf >>>>>>> 1. Change Listen setting to port 8888 on public IP >>>>>>> 2. Append the following to load and configure mod_jk: >>>>>>> >>>>>>> LoadModule jk_module modules/mod_jk.so >>>>>>> JkWorkersFile $TESTDIR/httpd/conf/workers.**properties >>>>>>> JkShmFile $TESTDIR/httpd/logs/mod_jk.shm >>>>>>> JkLogFile $TESTDIR/httpd/logs/mod_jk.log >>>>>>> JkLogLevel info >>>>>>> JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " >>>>>>> JkMount /rs-test/* worker1 >>>>>>> >>>>>>> 2. Create $TESTDIR/httpd/conf/workers.**properties with the >>>>>>> following content: >>>>>>> >>>>>>> worker.list=worker1 >>>>>>> worker.worker1.type=ajp13 >>>>>>> worker.worker1.host=localhost >>>>>>> worker.worker1.port=8009 >>>>>>> >>>>>>> 6. Configure TomEE and create test app >>>>>>> 1. Edit conf/server.xml: >>>>>>> 1. Add jvmRoute="worker1" to engine configuration >>>>>>> 2. Change Engine "defaultHost" and Host "name" values to >>>>>>> external host name >>>>>>> 2. Create test application >>>>>>> 1. Create webapps/rs-test/WEB-INF/**classes/test >>>>> directory. >>>>>>> 2. Create >>>>> webapps/rs-test/WEB-INF/**classes/test/TestRS.java >>>>>>> with >>>>>>> the following content: >>>>>>> >>>>>>> package test; >>>>>>> import java.net.URI; >>>>>>> import javax.servlet.http.**HttpServletRequest; >>>>>>> import javax.ws.rs.*; >>>>>>> import javax.ws.rs.core.*; >>>>>>> @Path("") >>>>>>> public class TestRS { >>>>>>> >>>>>>> @GET >>>>>>> @Produces({MediaType.TEXT_**PLAIN}) >>>>>>> public String defaultPage(@Context UriInfo uriInfo, >>>>>>> @Context HttpHeaders hh, @Context >>>>>>> HttpServletRequest httpServletRequest) { >>>>>>> String response = >>>>>>> "uriInfo.getAbsolutePath(): " >>>>>>> + uriInfo.getAbsolutePath() + "\n" >>>>>>> + "uriInfo.getBaseUri(): " >>>>>>> + uriInfo.getBaseUri() + "\n" >>>>>>> + "uriInfo.getRequestUri(): " >>>>>>> + uriInfo.getRequestUri() + "\n" >>>>>>> + "httpServletRequest.**getLocalAddr(): " >>>>>>> + httpServletRequest.**getLocalAddr() + "\n" >>>>>>> + "httpServletRequest.**getLocalName(): " >>>>>>> + httpServletRequest.**getLocalName() + "\n" >>>>>>> + "httpServletRequest.**getLocalPort(): " >>>>>>> + httpServletRequest.**getLocalPort() + "\n" >>>>>>> + "httpServletRequest.**getServerName(): " >>>>>>> + httpServletRequest.**getServerName() + "\n" >>>>>>> + "httpServletRequest.**getServerPort(): " >>>>>>> + httpServletRequest.**getServerPort() + >> "\n\n"; >>>>>>> for (String header : >>>>> hh.getRequestHeaders().keySet(**)) >>>>>>> { >>>>>>> response += header + ":\n"; >>>>>>> for (String value : >>>>>>> hh.getRequestHeaders().get(**header)) { >>>>>>> response += "\t" + value + "\n"; >>>>>>> } >>>>>>> } >>>>>>> return response; >>>>>>> } >>>>>>> } >>>>>>> >>>>>>> 3. Compile test class with javac -classpath >>>>>>> lib/javaee-api-6.0-4-tomcat.**jar:lib/servlet-api.jar >>>>>>> webapps/rs-test/WEB-INF/**classes/test/TestRS.java >>>>>>> >>>>>>> 7. Start services >>>>>>> 1. Run apache-tomee-jaxrs-1.5.1/bin/**startup.sh to start TomEE >>>>>>> 2. Run httpd/bin/apachectl start to start httpd. >>>>>>> >>>>>>> >>>>>>> >>>>>>> On Wed, Feb 6, 2013 at 1:17 AM, Romain Manni-Bucau < >>>>> [email protected]<mailto: >>>>>>> [email protected]>**> wrote: >>>>>>> >>>>>>> UriInfo matches the http request info... >>>>>>> Le 6 févr. 2013 07:16, "Chet Hosey" <[email protected] >>>>>>> <mailto:[email protected]>> a écrit : >>>>>>> >>>>>>> >>>>>>>> After building httpd 2.2.23 and mod_jk 1.2.37, I configured an >>>>>>> AJP proxy >>>>>>>> for the TomEE test instance and set the jvmRoute in server.xml to >>>>>>> match the >>>>>>>> worker name from workers.properties. >>>>>>>> >>>>>>>> A request through httpd shows httpd's port number for the >>>>>>>> httpServletRequest methods, but still shows the TomEE HTTP >>>>>>> connector port >>>>>>>> in the URIs returned by the uriInfo methods. >>>>>>>> >>>>>>>> Doing string replacements seems fairly inelegant but I suppose >>>>>>> it's an >>>>>>>> option for custom apps. It would be surprising to learn that the >>>>>>> only other >>>>>>>> option is to configure the TomEE instances' HTTP connectors on >>>>>>> the same >>>>>>>> port as the httpd server, since each TomEE instance would then need >> a >>>>>>>> dedicated IP. >>>>>>>> >>>>>>>> I've filed TOMEE-757 in JIRA, as it's hard to imagine that this >>>>>>> behavior is >>>>>>>> intended. >>>>>>>> >>>>>>>> >>>>>>>> On Tue, Feb 5, 2013 at 9:17 AM, Chet Hosey <[email protected] >>>>>>> <mailto:[email protected]>> wrote: >>>>>>>> >>>>>>>>> Ahh, that's a good thought. It was the default value of >>>>>>> "localhost". >>>>>>>> After >>>>>>>>> changing the "name" attribute on the Host entry and updating the >>>>>>>>> defaultHost on the Engine, I'm getting the expected host name >>>>>>> in the >>>>>>>>> response. >>>>>>>>> >>>>>>>>> This leads me to wonder what happens when using AJP. I'm >>>>>>> picturing a >>>>>>>> setup >>>>>>>>> where httpd runs on port 80 and proxies to multiple TomEE >>>>>>> instances via >>>>>>>>> AJP. If the HTTP connector port is still used by the UriInfo >>>>>>> methods, >>>>>>>> then >>>>>>>>> TomEE would require special access (root or authbind) to bind >>>>>>> to port 80 >>>>>>>> to >>>>>>>>> work around this behavior. And it wouldn't be possible to run >>>>>>> multiple >>>>>>>>> TomEE instances on the same IP, since they'd all have to bind >>>>>>> to port 80 >>>>>>>> to >>>>>>>>> ensure URI correctness. >>>>>>>>> >>>>>>>>> I'll have to experiment to find out. If I get the chance to do >>>>>>> so, I'll >>>>>>>>> report results back. >>>>>>>>> >>>>>>>>> Thanks! >>>>>>>>> >>>>>>>>> >>>>>>>>> On Tue, Feb 5, 2013 at 1:16 AM, Romain Manni-Bucau < >>>>>>>> [email protected] <mailto:[email protected]>**>wrote: >>>>>>> >>>>>>>>> >>>>>>>>>> Hi, >>>>>>>>>> >>>>>>>>>> What's your host in the server.xml? >>>>>>>>>> Le 5 févr. 2013 06:30, "Chet Hosey" <[email protected] >>>>>>> <mailto:[email protected]>> a écrit : >>>>>>> >>>>>>>>>> >>>>>>>>>>> I've been using apache-tomee-1.5.1-jaxrs as a platform for >>>>>>> learning >>>>>>>>>> JAX-RS >>>>>>>>>>> and have run into some confusion about UriInfo determines >>>>>>> the base >>>>>>>> URI. >>>>>>>>>> In >>>>>>>>>>> my testing the URIs returned by UriInfo include the correct port >>>>>>>> number. >>>>>>>>>>> But the host name is always "localhost", even when I'm >>>>>>> accessing TomEE >>>>>>>>>> from >>>>>>>>>>> a remote machine. >>>>>>>>>>> >>>>>>>>>>> It's possible that UriInfo is meant to build identifiers, >>>>>>> and not >>>>>>>>>> locators. >>>>>>>>>>> This would explain why it's not called UrlInfo. But the >>>>>>> design of >>>>>>>>>>> UriBuilder suggests that one should be able to call >>>>>>>>>>> >>>>>>>>>>> uriInfo.getBaseUriBuilder() >>>>>>>>>>> .path(User.class, "getUserInfo") >>>>>>>>>>> .path(userId).build(); >>>>>>>>>>> >>>>>>>>>>> and use the result as a hyperlink in a JAX-RS response. >>>>>>>>>>> >>>>>>>>>>> Having used mod_jk with JBoss, I know that it can override >>>>>>> the values >>>>>>>>>>> returned by HttpServletRequest methods with parameters like >>>>>>>>>> JK_LOCAL_NAME. >>>>>>>>>>> But since this is just a sandbox I'm accessing Tomcat directly, >>>>>>>> without >>>>>>>>>> an >>>>>>>>>>> Apache httpd proxy. But this led me to wonder what >>>>>>>>>>> httpServletRequest.**getlocalName() would return. So I created >>>>>>> a test >>>>>>>>>> method >>>>>>>>>>> to find out, using the following signature: >>>>>>>>>>> >>>>>>>>>>> @GET >>>>>>>>>>> @Produces({MediaType.TEXT_**PLAIN}) >>>>>>>>>>> public String defaultPage(@Context UriInfo uriInfo, >>>>>>>>>>> @Context HttpHeaders hh, >>>>>>>>>>> @Context HttpServletRequest httpServletRequest) { >>>>>>>>>>> >>>>>>>>>>> The output surprised me. The HttpServletRequest methods use the >>>>>>>> correct >>>>>>>>>>> host name and IP address, and the "Host" header uses the public >>>>>>>> address. >>>>>>>>>>> The UriInfo methods get the port correct, but they still use >>>>>>>>>> "localhost" as >>>>>>>>>>> the host name. >>>>>>>>>>> >>>>>>>>>>> uriInfo.getAbsolutePath(): >>>>>>>>>>> http://localhost:8081/sample-**app-1.0-SNAPSHOT/< >>>>> http://localhost:8081/sample-app-1.0-SNAPSHOT/> >>>>>>>>>>> uriInfo.getBaseUri(): >>>>>>>> http://localhost:8081/sample-**app-1.0-SNAPSHOT< >>>>> http://localhost:8081/sample-app-1.0-SNAPSHOT> >>>>>>>>>>> uriInfo.getRequestUri(): >>>>>>>>>> http://localhost:8081/sample-**app-1.0-SNAPSHOT/< >>>>> http://localhost:8081/sample-app-1.0-SNAPSHOT/> >>>>>>>>>>> httpServletRequest.**getLocalAddr(): 1.2.3.4 >>>>>>>>>>> httpServletRequest.**getLocalName(): www.example.com >>>>>>> <http://www.example.com> >>>>>>>>>>> httpServletRequest.**getLocalPort(): 8081 >>>>>>>>>>> httpServletRequest.**getServerName(): www.example.com >>>>>>> <http://www.example.com> >>>>>>>>>>> httpServletRequest.**getServerPort(): 8081 >>>>>>>>>>> >>>>>>>>>>> host: >>>>>>>>>>> www.example.com:8081 <http://www.example.com:8081> >>>>>>> >>>>>>>>>>> >>>>>>>>>>> Is there a way to use TomEE's embedded CXF REST >>>>>>> implementation to >>>>>>>>>> generate >>>>>>>>>>> URIs that can be used by external clients to locate other >>>>>>> resources >>>>>>>>>> within >>>>>>>>>>> the same application? Or am I making bad assumptions about >>>>>>> the purpose >>>>>>>>>> of >>>>>>>>>>> the UriInfo methods that return UriBuilders? >>>>>>>>>>> >>>>>>>>>>> -- Chet >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>> >>>>> >> >>
