This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.commons.fsclassloader-1.0.4 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-commons-fsclassloader.git
commit 37162e1adf8bfd9256ea0cd4f36ccba8c9d49292 Author: Radu Cotescu <[email protected]> AuthorDate: Fri Jun 17 16:16:54 2016 +0000 SLING-5601 - The File System Classloader Console Plugin should allow wiping the classloader's cache * added support for clearing the classloader through the web console plug-in git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/fsclassloader@1748876 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 36 ++++++-- .../impl/FSClassLoaderWebConsole.java | 59 +++++++++++-- src/main/resources/res/ui/fsclassloader.js | 69 +++++++++++++++ .../impl/FSClassLoaderWebConsoleTest.java | 98 ++++++++++++++++++++++ 4 files changed, 250 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 9a66f0c..dc456de 100644 --- a/pom.xml +++ b/pom.xml @@ -120,11 +120,35 @@ <version>2.5</version> <scope>provided</scope> </dependency> - <dependency> - <groupId>org.apache.felix</groupId> - <artifactId>org.apache.felix.webconsole</artifactId> - <version>3.0.0</version> - <scope>provided</scope> - </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.webconsole</artifactId> + <version>3.0.0</version> + <scope>provided</scope> + </dependency> + + <!-- Testing --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>1.6.5</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java index 359fe71..ee5f6a0 100644 --- a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java +++ b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java @@ -39,9 +39,13 @@ import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.apache.felix.webconsole.AbstractWebConsolePlugin; +import org.apache.sling.commons.classloader.ClassLoaderWriter; import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Web Console for the FileSystem Class Loader. Allows users to download Java @@ -62,6 +66,12 @@ public class FSClassLoaderWebConsole extends AbstractWebConsolePlugin { static final String APP_ROOT = "fsclassloader"; static final String RES_LOC = APP_ROOT + "/res/ui"; + static final String POST_PARAM_CLEAR_CLASSLOADER = "clear"; + + private static final Logger LOG = LoggerFactory.getLogger(FSClassLoaderWebConsole.class); + + @Reference(target = "(service.pid=org.apache.sling.commons.fsclassloader.impl.FSClassLoaderProvider)") + private ClassLoaderWriter classLoaderWriter; /** * Represents a set of class, java and deps files for a script. @@ -205,11 +215,42 @@ public class FSClassLoaderWebConsole extends AbstractWebConsolePlugin { IOUtils.copy( getClass().getClassLoader().getResourceAsStream( "/res/ui/prettify.js"), response.getOutputStream()); - } else { + } else if (request.getRequestURI().endsWith(RES_LOC + "/fsclassloader.js")) { + response.setContentType("application/javascript"); + IOUtils.copy( + getClass().getClassLoader().getResourceAsStream( + "/res/ui/fsclassloader.js"), response.getOutputStream()); + } + else { super.doGet(request, response); } } + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String clear = req.getParameter(POST_PARAM_CLEAR_CLASSLOADER); + boolean shouldClear = Boolean.parseBoolean(clear); + if (shouldClear) { + if (classLoaderWriter != null) { + boolean result = classLoaderWriter.delete(""); + if (result) { + resp.getWriter().write("{ \"status\" : \"success\" }"); + resp.setStatus(HttpServletResponse.SC_OK); + } else { + resp.getWriter().write("{ \"status\" : \"failure\", \"message\" : \"unable to clear classloader; check server log\" }"); + resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } else { + LOG.error("Cannot get a reference to org.apache.sling.commons.fsclassloader.impl.FSClassLoaderProvider"); + resp.getWriter().write("{ \"status\" : \"failure\", \"message\" : \"unable to clear classloader; check server log\" }"); + resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } else { + resp.getWriter().write("{ \"status\" : \"failure\", \"message\" : \"invalid command\" }"); + resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + } + /* * (non-Javadoc) * @@ -328,10 +369,13 @@ public class FSClassLoaderWebConsole extends AbstractWebConsolePlugin { + "/prettify.css\"></link>"); w.write("<script type=\"text/javascript\" src=\"" + RES_LOC + "/prettify.js\"></script>"); + w.write("<script type=\"text/javascript\" src=\"" + RES_LOC + + "/fsclassloader.js\"></script>"); w.write("<script>$(document).ready(prettyPrint);</script>"); w.write("<style>.prettyprint ol.linenums > li { list-style-type: decimal; } pre.prettyprint { white-space: pre-wrap; }</style>"); String file = request.getParameter("view"); File toView = new File(root + file); + w.write("<div id=\"classes\">"); if (!StringUtils.isEmpty(file)) { if (isValid(toView)) { @@ -363,7 +407,7 @@ public class FSClassLoaderWebConsole extends AbstractWebConsolePlugin { InputStream is = null; try { is = new FileInputStream(toView); - String contents = IOUtils.toString(is); + String contents = IOUtils.toString(is, "UTF-8"); w.write("<pre class=\"prettyprint linenums\">"); w.write(StringEscapeUtils.escapeHtml4(contents)); w.write("</pre>"); @@ -374,11 +418,13 @@ public class FSClassLoaderWebConsole extends AbstractWebConsolePlugin { response.sendError(404, "File " + file + " not found"); } } else { - w.write("<p class=\"statline ui-state-highlight\">File System ClassLoader Root: " - + root + "</p>"); - - w.write("<table class=\"nicetable ui-widget\">"); + + root + " <span style=\"float: right\"><button type='button' id='clear'>Clear Class Loader</button></span></p>"); + if (scripts.values().size() > 0 ) { + w.write("<table class=\"nicetable ui-widget fsclassloader-has-classes\">"); + } else { + w.write("<table class=\"nicetable ui-widget\">"); + } w.write("<tr class=\"header ui-widget-header\">"); w.write("<th>View</th>"); w.write("<th>Script</th>"); @@ -395,5 +441,6 @@ public class FSClassLoaderWebConsole extends AbstractWebConsolePlugin { } w.write("</table>"); } + w.write("</div>"); } } diff --git a/src/main/resources/res/ui/fsclassloader.js b/src/main/resources/res/ui/fsclassloader.js new file mode 100644 index 0000000..4eca6e3 --- /dev/null +++ b/src/main/resources/res/ui/fsclassloader.js @@ -0,0 +1,69 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +(function () { + 'use strict'; + + $(document).ready(function () { + toggleButton(hasClasses()); + + $('#clear').on('click', function (e) { + e.preventDefault(); + var classes = hasClasses(); + if (classes) { + clearCache(); + toggleButton(classes); + } + + }); + }); + + function clearCache() { + $.ajax({ + type: 'POST', + data: {'clear': true}, + dataType: 'json', + global: false + }).success( + function () { + window.location.reload(); + } + ).fail( + function (jqXHR) { + var response, message; + try { + response = JSON.parse(jqXHR.responseText); + message = response.message; + } catch (err) { + // do nothing + } + if (message) { + alert('Error: ' + message); + } else { + alert('An unknown error was encountered. Please check the server logs.'); + } + } + ); + } + + function hasClasses () { + return $('table.fsclassloader-has-classes').length > 0; + } + + function toggleButton(toggle) { + $('#clear').attr('disabled', !toggle); + } +})(); diff --git a/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java b/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java new file mode 100644 index 0000000..1f7511c --- /dev/null +++ b/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.apache.sling.commons.fsclassloader.impl; + +import java.io.PrintWriter; +import java.io.StringWriter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.sling.commons.classloader.ClassLoaderWriter; +import org.junit.After; +import org.junit.Test; +import org.mockito.Mockito; +import org.powermock.reflect.Whitebox; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; + +public class FSClassLoaderWebConsoleTest { + + private FSClassLoaderWebConsole console; + private ClassLoaderWriter classLoaderWriter; + + @After + public void after() { + console = null; + classLoaderWriter = null; + } + + @Test + public void testClearClassLoaderOK() throws Exception { + setFixture(true); + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + when(response.getWriter()).thenReturn(writer); + when(request.getParameter(FSClassLoaderWebConsole.POST_PARAM_CLEAR_CLASSLOADER)).thenReturn("true"); + console.doPost(request, response); + verify(classLoaderWriter).delete(""); + verify(response).setStatus(HttpServletResponse.SC_OK); + assertEquals("{ \"status\" : \"success\" }", stringWriter.toString()); + } + + @Test + public void testClearClassLoaderWrongCommand() throws Exception { + setFixture(true); + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + when(response.getWriter()).thenReturn(writer); + when(request.getParameter(FSClassLoaderWebConsole.POST_PARAM_CLEAR_CLASSLOADER)).thenReturn("random"); + console.doPost(request, response); + verify(classLoaderWriter, Mockito.times(0)).delete(""); + verify(response).setStatus(HttpServletResponse.SC_BAD_REQUEST); + assertEquals("{ \"status\" : \"failure\", \"message\" : \"invalid command\" }", stringWriter.toString()); + } + + @Test + public void testClearClassLoaderUnableToClean() throws Exception { + setFixture(false); + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + when(response.getWriter()).thenReturn(writer); + when(request.getParameter(FSClassLoaderWebConsole.POST_PARAM_CLEAR_CLASSLOADER)).thenReturn("true"); + console.doPost(request, response); + verify(classLoaderWriter).delete(""); + verify(response).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + assertEquals("{ \"status\" : \"failure\", \"message\" : \"unable to clear classloader; check server log\" }", + stringWriter.toString()); + } + + private void setFixture(boolean clwReturn) { + console = spy(new FSClassLoaderWebConsole()); + classLoaderWriter = mock(ClassLoaderWriter.class); + when(classLoaderWriter.delete("")).thenReturn(clwReturn); + Whitebox.setInternalState(console, "classLoaderWriter", classLoaderWriter); + } + + +} -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
