6 Replies Latest reply on Dec 4, 2013 11:30 AM by matt.drees

    HornetQ-REST HTTP-405 (Method Not Allowed) for GET, HEAD on queues

    sumitsu

      I am unable to query the queue/topic resources via the HornetQ REST API using either the Wildfly AS 8.0.0-alpha4 release or the Wildfly master/head revision (downloaded and built as of yesterday).

       

      Per the setup instructions, I've deployed a WAR (in exploded state) with the following contents:

       

      HornetQ-REST.war
      HornetQ-REST.war/WEB-INF
      HornetQ-REST.war/WEB-INF/lib
      HornetQ-REST.war/WEB-INF/lib/hornetq-rest-2.4.0.Beta1.jar
      HornetQ-REST.war/WEB-INF/web.xml
      HornetQ-REST.war/WEB-INF/classes
      HornetQ-REST.war/WEB-INF/classes/hornetq-rest.conf.xml
      HornetQ-REST.war/META-INF
      HornetQ-REST.war/META-INF/MANIFEST.MF
      

       

      I've attached a non-exploded version of the WAR to this post.  (hornetq-rest-2.4.0.Beta1.jar is just the hornetq-rest.jar file included with the 2.4.0.Beta1 distribution, renamed for my clarity / tracking purposes.)

       

      According to the HornetQ documentation, performing an HTTP GET or HEAD on the URL queues/{queue-name} (relative to the context path) should provide a response with headers like the following:

       

      Server: Apache-Coyote/1.1
      msg-pull-consumers: http://127.0.0.1:13510/HornetQ-REST/queues/jms.queue.sumitsu/pull-consumers
      msg-create-with-id: http://127.0.0.1:13510/HornetQ-REST/queues/jms.queue.sumitsu/create/{id}
      msg-create: http://127.0.0.1:13510/HornetQ-REST/queues/jms.queue.sumitsu/create
      msg-push-consumers: http://127.0.0.1:13510/HornetQ-REST/queues/jms.queue.sumitsu/push-consumers
      Content-Length: 0
      Date: Tue, 10 Sep 2013 21:43:04 GMT
      

       

      Instead, I'm getting an HTTP-405 "Method Not Allowed" response for both GET and HEAD, and indeed if I perform an OPTIONS request, GET and HEAD are not listed:

       

      Allow: DELETE, OPTIONS
      Connection: keep-alive
      Content-Type: text/plain
      Content-Length: 15
      
      

       

      By contrast, when I deploy the same HornetQ-REST WAR to JBossAS 7.2.0.Final, then perform the same OPTIONS request, I get this:

       

      Server: Apache-Coyote/1.1
      Allow: GET, OPTIONS, HEAD
      Content-Length: 0
      Date: Tue, 10 Sep 2013 21:46:43 GMT
      
      

       

      Other REST API calls appear to be working.  For example, I can create and destroy destinations, and I appear to be able to publish messages.  (I have not yet tried adding consumers.)

       

      Am I doing something wrong in my Wildfly test, or is there a bug?  If the latter, I'd assume that it would be a bug in Wildfly rather than HornetQ (since the JAX-RS-annotated REST endpoints are included in the WAR in hornetq-rest-2.4.0.Beta1.jar, and thus should be the same in both my Wildfly 8.0.0 and my JBossAS 7.2.0 test cases), but I could be wrong.

        • 1. Re: HornetQ-REST HTTP-405 (Method Not Allowed) for GET, HEAD on queues
          jmesnil

          WildFly has changed its default Web container to Undertow.

          From your description, it seems that Undertow does not consider GET and HEAD as allowed method for the queue resource and there might be an issue when extracting this metadata from the WAR.

           

          Could you open a bug in its issue tracker? http://undertow.io/get-involved.html

          • 2. Re: HornetQ-REST HTTP-405 (Method Not Allowed) for GET, HEAD on queues
            ctomc

            Exception originates from Jax-rs integration, not from undertow...

             

            full stacktrace:

             

            11:40:24,214 WARN  [org.jboss.resteasy.core.ExceptionHandler] (default task-1) failed to execute: javax.ws.rs.NotAllowedException: No resource method found for GET, return 405 with Allow header

                    at org.jboss.resteasy.core.registry.SegmentNode.match(SegmentNode.java:371) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.core.registry.SegmentNode.match(SegmentNode.java:114) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.core.registry.RootNode.match(RootNode.java:43) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.core.registry.RootClassNode.match(RootClassNode.java:48) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.core.ResourceMethodRegistry.getResourceInvoker(ResourceMethodRegistry.java:444) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.core.SynchronousDispatcher.getInvoker(SynchronousDispatcher.java:234) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.core.SynchronousDispatcher.invokePropagateNotFound(SynchronousDispatcher.java:202) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:224) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:62) [resteasy-jaxrs-3.0.4.Final.jar:]

                    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:56) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:59) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:81)

                    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:65) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:70) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:209) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:196) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:69) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:130) [undertow-servlet-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.server.HttpHandlers.executeRootHandler(HttpHandlers.java:36) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:614) [undertow-core-1.0.0.Beta13.jar:1.0.0.Beta13]

                    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_21]

                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_21]

                    at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_21]

            • 3. Re: Re: HornetQ-REST HTTP-405 (Method Not Allowed) for GET, HEAD on queues
              matt.drees

              I bumped into this as well.

               

              I think it's an issue related to Resteasy 3.  I get an identical error when I run the hornetq jms-to-rest example after changing the resteasy version from 2.3.4.Final to 3.0.4.Final:

               

              $ mvn jetty:run
              [INFO] Scanning for projects...
              <snip>
              [INFO] ------------------------------------------------------------------------
              [INFO] Building Mixed JMS and REST Producers/Consumers 2.4.0.Beta1
              [INFO] ------------------------------------------------------------------------
              <snip>
              [INFO] --- maven-jetty-plugin:6.1.15:run (default-cli) @ mixed-jms-rest ---
              [INFO] Configuring Jetty for project: Mixed JMS and REST Producers/Consumers
              [INFO] Webapp source directory = /Users/mattdrees/Downloads/hornetq-2.4.0.Beta1/examples/jms/rest/jms-to-rest/src/main/webapp
              [INFO] Reload Mechanic: automatic
              [INFO] web.xml file = /Users/mattdrees/Downloads/hornetq-2.4.0.Beta1/examples/jms/rest/jms-to-rest/src/main/webapp/WEB-INF/web.xml
              [INFO] Classes = /Users/mattdrees/Downloads/hornetq-2.4.0.Beta1/examples/jms/rest/jms-to-rest/target/classes
              [INFO] Logging to org.slf4j.impl.SimpleLogger(org.mortbay.log) via org.mortbay.log.Slf4jLog
              [INFO] Context path = /
              [INFO] Tmp directory =  determined at runtime
              [INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml
              [INFO] Web overrides =  none
              [INFO] Webapp directory = /Users/mattdrees/Downloads/hornetq-2.4.0.Beta1/examples/jms/rest/jms-to-rest/src/main/webapp
              [INFO] Starting jetty 6.1.15 ...
              [INFO] jetty-6.1.15
              [INFO] No Transaction manager found - if your webapp requires one, please configure one.
              Nov 27, 2013 1:14:43 PM org.hornetq.core.deployers.impl.FileConfigurationParser parseMainConfig
              WARN: HQ222018: AIO was not located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO to enable the AIO journal
              Nov 27, 2013 1:14:43 PM org.hornetq.core.server.impl.HornetQServerImpl start
              INFO: HQ221000: live server is starting with configuration HornetQ Configuration (clustered=false,backup=false,sharedStore=true,journalDirectory=data/journal,bindingsDirectory=data/bindings,largeMessagesDirectory=data/largemessages,pagingDirectory=data/paging)
              Nov 27, 2013 1:14:43 PM org.hornetq.core.server.impl.HornetQServerImpl initialisePart1
              WARN: HQ222007: Security risk! HornetQ is running with the default cluster admin user and default password. Please see the HornetQ user guide, cluster chapter, for instructions on how to change this.
              Nov 27, 2013 1:14:43 PM org.hornetq.core.server.impl.HornetQServerImpl deployQueue
              INFO: HQ221003: trying to deploy queue jms.queue.orders
              Nov 27, 2013 1:14:43 PM org.hornetq.core.remoting.impl.netty.NettyAcceptor start
              INFO: HQ221020: Started Netty Acceptor version 3.6.6.Final-90e1eb2 localhost:5445 for CORE protocol
              Nov 27, 2013 1:14:43 PM org.hornetq.core.server.impl.HornetQServerImpl$SharedNothingLiveActivation run
              INFO: HQ221007: Server is now live
              Nov 27, 2013 1:14:43 PM org.hornetq.core.server.impl.HornetQServerImpl start
              INFO: HQ221001: HornetQ Server version 2.4.0.Beta1 (Andromedian Fly paper, 123) [f21e4523-577f-11e3-b370-991f6b6af0b9] 
              [INFO] Started SelectChannelConnector@0.0.0.0:9095
              [INFO] Started Jetty Server
              [INFO] Starting scanner at interval of 2 seconds.
              13717 [844500369@qtp-1575248128-0] ERROR org.jboss.resteasy.core.ExceptionHandler - failed to execute
              javax.ws.rs.NotAllowedException: No resource method found for HEAD, return 405 with Allow header
                at org.jboss.resteasy.core.registry.SegmentNode.match(SegmentNode.java:371)
                at org.jboss.resteasy.core.registry.SegmentNode.match(SegmentNode.java:114)
                at org.jboss.resteasy.core.registry.RootNode.match(RootNode.java:43)
                at org.jboss.resteasy.core.registry.RootClassNode.match(RootClassNode.java:48)
                at org.jboss.resteasy.core.ResourceMethodRegistry.getResourceInvoker(ResourceMethodRegistry.java:444)
                at org.jboss.resteasy.core.SynchronousDispatcher.getInvoker(SynchronousDispatcher.java:234)
                at org.jboss.resteasy.core.SynchronousDispatcher.invokePropagateNotFound(SynchronousDispatcher.java:202)
                at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:224)
                at org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:62)
                at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1139)
                at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:378)
                at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
                at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
                at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
                at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)
                at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
                at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
                at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
                at org.mortbay.jetty.Server.handle(Server.java:324)
                at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:535)
                at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:865)
                at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)
                at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
                at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
                at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
                at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:520)
              
              • 4. Re: Re: Re: HornetQ-REST HTTP-405 (Method Not Allowed) for GET, HEAD on queues
                matt.drees

                So, I decide to dive into debugging this.  It seems the root cause is a change in RestEasy's request-matching logic.  The new behavior seems to be mandated by the jax-rs spec.  (Perhaps the old behavior was a bug?)

                 

                So, the QueueDestinationsResource looks something like this:

                @Path(Constants.PATH_FOR_QUEUES)
                public class QueueDestinationsResource
                {
                   @DELETE("/{queue-name}")
                   public void deleteQueue(@Context UriInfo uriInfo, @PathParam("queue-name") String name) throws Exception
                   { ... }
                
                
                
                   @Path("/{queue-name}")
                   public synchronized QueueResource findQueue(@PathParam("queue-name") String name) throws Exception
                   { ... }
                
                }
                

                 

                So, a request for /queues/1234 matches both the deleteQueue() sub-resource method and the findQueue() sub-resource locator.

                 

                RestEasy 3.0.4 lets sub-resource methods trump sub-resource locators entirely.  Relevant code in SegmentNode.java:

                   public ResourceInvoker match(HttpRequest request, int start)
                    {
                       List<MethodExpression> potentials = ...
                 
                       boolean expressionMatched = false;
                       List<Match> matches = new ArrayList<Match>();
                       for (MethodExpression expression : potentials)
                       {
                          // We ignore locators if the first match was a resource method as per the spec Section 3, Step 2(h)
                          if (expressionMatched && expression.isLocator()) continue;
                          ...
                
                       }
                       ...
                
                     }
                

                The `potentials` list is populated with both methods, but the `matches` list only gets filled with the deleteQueue() method.  This is why the HEAD request is dying, and jax-rs thinks that only DELETE (and OPTIONS) are available request methods.

                 

                Note the comment.  I checked the spec, and though I don't follow it entirely, it does seem to indicate that RestEasy is now doing the right thing.

                 

                So, it appears hornetq-rest is not spec-compliant, and should be fixed.

                • 5. Re: Re: Re: HornetQ-REST HTTP-405 (Method Not Allowed) for GET, HEAD on queues
                  matt.drees

                  I am taking a crack at fixing this.  Work is here: mattdrees/hornetq · GitHub

                  • 6. Re: Re: Re: HornetQ-REST HTTP-405 (Method Not Allowed) for GET, HEAD on queues
                    matt.drees

                    sumitsu, this is fixed in master now.  Justin merged my pull request yesterday.