Repository: ambari Updated Branches: refs/heads/trunk c775c6071 -> c8032c6d1
AMBARI-9551 - Views: ContextClassLoader can't load resources for JARs (tbeerbower) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c8032c6d Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c8032c6d Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c8032c6d Branch: refs/heads/trunk Commit: c8032c6d13dd3cf3afb1d6cb76ec48dd19782031 Parents: c775c60 Author: tbeerbower <tbeerbo...@hortonworks.com> Authored: Tue Feb 10 15:09:06 2015 -0500 Committer: tbeerbower <tbeerbo...@hortonworks.com> Committed: Tue Feb 10 15:09:35 2015 -0500 ---------------------------------------------------------------------- .../server/controller/AmbariHandlerList.java | 69 ++++++++++++++++++++ .../server/controller/FailsafeHandlerList.java | 25 +++++-- .../controller/AmbariHandlerListTest.java | 65 ++++++++++++++++++ 3 files changed, 154 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/c8032c6d/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java index da15a66..7c68311 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariHandlerList.java @@ -17,11 +17,18 @@ */ package org.apache.ambari.server.controller; +import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.inject.Inject; import javax.inject.Singleton; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.apache.ambari.server.orm.entities.ViewEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntity; @@ -31,10 +38,13 @@ import org.apache.ambari.server.view.ViewRegistry; import org.apache.ambari.view.SystemException; import org.apache.ambari.view.ViewContext; import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.SessionManager; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.webapp.WebAppContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.filter.DelegatingFilterProxy; @@ -47,6 +57,12 @@ import org.springframework.web.filter.DelegatingFilterProxy; public class AmbariHandlerList extends FailsafeHandlerList implements ViewInstanceHandlerList { /** + * The target pattern for a view resource request. + */ + private static final Pattern VIEW_RESOURCE_TARGET_PATTERN = + Pattern.compile("/api/(\\S+)/views/(\\S+)/versions/(\\S+)/instances/(\\S+)/resources/(\\S+)"); + + /** * The view registry. */ @Inject @@ -76,6 +92,12 @@ public class AmbariHandlerList extends FailsafeHandlerList implements ViewInstan */ private GenericWebApplicationContext springWebAppContext; + /** + * The logger. + */ + protected final static Logger LOG = LoggerFactory.getLogger(AmbariHandlerList.class); + + // ----- Constructors ------------------------------------------------------ /** @@ -122,6 +144,39 @@ public class AmbariHandlerList extends FailsafeHandlerList implements ViewInstan } + // ----- FailsafeHandlerList ----------------------------------------------- + + @Override + protected void handleNonFailSafe(String target, Request baseRequest, + HttpServletRequest request, HttpServletResponse response, + List<Handler> handlers) throws IOException, ServletException { + + ViewEntity viewEntity = getTargetView(target); + + if (viewEntity == null) { + super.handleNonFailSafe(target, baseRequest, request, response, handlers); + } else { + // if there is a view target (as in a view resource request) then set the view class loader + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader viewClassLoader = null; + + try { + viewClassLoader = viewEntity.getClassLoader(); + if (viewClassLoader == null) { + LOG.warn("No class loader associated with view " + viewEntity.getName() + "."); + } else { + Thread.currentThread().setContextClassLoader(viewClassLoader); + } + super.handleNonFailSafe(target, baseRequest, request, response, handlers); + } finally { + if (viewClassLoader != null) { + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + } + } + } + + // ----- ViewInstanceHandler ----------------------------------------------- @Override @@ -167,6 +222,20 @@ public class AmbariHandlerList extends FailsafeHandlerList implements ViewInstan } + /** + * Get the view that is the target of the request; null if not a view request. + * + * @param target the target of the request + * + * @return the view target; null if none + */ + private ViewEntity getTargetView(String target) { + Matcher matcher = VIEW_RESOURCE_TARGET_PATTERN.matcher(target); + + return matcher.matches() ? viewRegistry.getDefinition(matcher.group(2), matcher.group(3)) : null; + } + + // ----- inner interface : HandlerFactory ---------------------------------- /** http://git-wip-us.apache.org/repos/asf/ambari/blob/c8032c6d/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java index fa1e6b1..26395cc 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java @@ -127,12 +127,27 @@ public class FailsafeHandlerList extends HandlerCollection { return; } } + handleNonFailSafe(target, baseRequest, request, response, nonFailsafeHandlers); + } + } - for (Handler handler : nonFailsafeHandlers) { - handler.handle(target, baseRequest, request, response); - if (baseRequest.isHandled()) { - return; - } + /** + * Attempt to handle the request with the non-failsafe handlers. + * + * @param target the target of the request - either a URI or a name + * @param baseRequest the original unwrapped request object. + * @param request the request + * @param response the response + * @param handlers the non-failsafe handlers + */ + protected void handleNonFailSafe(String target, Request baseRequest, HttpServletRequest request, + HttpServletResponse response, List<Handler> handlers) + throws IOException, ServletException { + + for (Handler handler : handlers) { + handler.handle(target, baseRequest, request, response); + if (baseRequest.isHandled()) { + return; } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/c8032c6d/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java index 7171e88..04a4b15 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariHandlerListTest.java @@ -18,15 +18,25 @@ package org.apache.ambari.server.controller; +import org.apache.ambari.server.orm.entities.ViewEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntityTest; +import org.apache.ambari.server.view.ViewRegistry; import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.Assert; import org.junit.Test; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.expect; @@ -104,4 +114,59 @@ public class AmbariHandlerListTest { verify(handler, server); } + + @Test + public void testHandleNonFailSafe() throws Exception { + TestHandler handler = new TestHandler(); + AmbariHandlerList.HandlerFactory handlerFactory = createNiceMock(AmbariHandlerList.HandlerFactory.class); + ViewRegistry viewRegistry = createNiceMock(ViewRegistry.class); + ViewEntity viewEntity = createNiceMock(ViewEntity.class); + ClassLoader classLoader = createNiceMock(ClassLoader.class); + + Request baseRequest = createNiceMock(Request.class); + + HttpServletRequest request = createNiceMock(HttpServletRequest.class); + HttpServletResponse response = createNiceMock(HttpServletResponse.class); + + List <Handler> handlers = new LinkedList<Handler>(); + handlers.add(handler); + + expect(viewRegistry.getDefinition("TEST", "1.0.0")).andReturn(viewEntity).anyTimes(); + expect(viewEntity.getClassLoader()).andReturn(classLoader).anyTimes(); + + replay(viewRegistry, viewEntity); + + AmbariHandlerList handlerList = new AmbariHandlerList(handlerFactory); + handlerList.viewRegistry = viewRegistry; + + handlerList.handleNonFailSafe("/api/v1/views/TEST/versions/1.0.0/instances/INSTANCE_1/resources/test", + baseRequest, request, response, handlers); + + Assert.assertEquals("/api/v1/views/TEST/versions/1.0.0/instances/INSTANCE_1/resources/test", handler.getTarget()); + Assert.assertEquals(classLoader, handler.getClassLoader()); + + verify(viewRegistry, viewEntity); + } + + private static class TestHandler extends AbstractHandler { + + private ClassLoader classLoader = null; + private String target = null; + + @Override + public void handle(String target, Request request, + HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) + throws IOException, ServletException { + this.target = target; + classLoader = Thread.currentThread().getContextClassLoader(); + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public String getTarget() { + return target; + } + } }