Author: radu
Date: Fri Jun 17 16:16:54 2016
New Revision: 1748876

URL: http://svn.apache.org/viewvc?rev=1748876&view=rev
Log:
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

Added:
    
sling/trunk/bundles/commons/fsclassloader/src/main/resources/res/ui/fsclassloader.js
    sling/trunk/bundles/commons/fsclassloader/src/test/
    sling/trunk/bundles/commons/fsclassloader/src/test/java/
    sling/trunk/bundles/commons/fsclassloader/src/test/java/org/
    sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/
    sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/
    
sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/
    
sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/fsclassloader/
    
sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/fsclassloader/impl/
    
sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java
Modified:
    sling/trunk/bundles/commons/fsclassloader/pom.xml
    
sling/trunk/bundles/commons/fsclassloader/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java

Modified: sling/trunk/bundles/commons/fsclassloader/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fsclassloader/pom.xml?rev=1748876&r1=1748875&r2=1748876&view=diff
==============================================================================
--- sling/trunk/bundles/commons/fsclassloader/pom.xml (original)
+++ sling/trunk/bundles/commons/fsclassloader/pom.xml Fri Jun 17 16:16:54 2016
@@ -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>

Modified: 
sling/trunk/bundles/commons/fsclassloader/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fsclassloader/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java?rev=1748876&r1=1748875&r2=1748876&view=diff
==============================================================================
--- 
sling/trunk/bundles/commons/fsclassloader/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java
 (original)
+++ 
sling/trunk/bundles/commons/fsclassloader/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java
 Fri Jun 17 16:16:54 2016
@@ -39,9 +39,13 @@ import org.apache.felix.scr.annotations.
 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 ext
     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 ext
             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 ext
                 + "/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 ext
                 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 ext
                 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 ext
             }
             w.write("</table>");
         }
+        w.write("</div>");
     }
 }

Added: 
sling/trunk/bundles/commons/fsclassloader/src/main/resources/res/ui/fsclassloader.js
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fsclassloader/src/main/resources/res/ui/fsclassloader.js?rev=1748876&view=auto
==============================================================================
--- 
sling/trunk/bundles/commons/fsclassloader/src/main/resources/res/ui/fsclassloader.js
 (added)
+++ 
sling/trunk/bundles/commons/fsclassloader/src/main/resources/res/ui/fsclassloader.js
 Fri Jun 17 16:16:54 2016
@@ -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);
+    }
+})();

Added: 
sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java?rev=1748876&view=auto
==============================================================================
--- 
sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java
 (added)
+++ 
sling/trunk/bundles/commons/fsclassloader/src/test/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsoleTest.java
 Fri Jun 17 16:16:54 2016
@@ -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);
+    }
+
+
+}


Reply via email to