Index: jspwiki-war/src/main/java/org/apache/wiki/Release.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/Release.java	(revision 1622810)
+++ jspwiki-war/src/main/java/org/apache/wiki/Release.java	(working copy)
@@ -72,7 +72,7 @@
      *  <p>
      *  If the build identifier is empty, it is not added.
      */
-    public static final String     BUILD         = "6";
+    public static final String     BUILD         = "7";
 
     /**
      *  This is the generic version string you should use when printing out the version.  It is of 
Index: jspwiki-war/src/main/java/org/apache/wiki/WikiAjaxDispatcherServlet.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/WikiAjaxDispatcherServlet.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/WikiAjaxDispatcherServlet.java	(working copy)
@@ -0,0 +1,192 @@
+/*
+    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.wiki;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.imageio.spi.ServiceRegistry;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * This provides a simple ajax servlet for handling /ajax/ClassName requests.
+ * Classes need to be registered as per
+ * <a href="http://docs.oracle.com/javase/1.5.0/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html">ServiceRegistry</a>
+ * Add your custom servlets to the file <b>META-INF/services/javax.servlet.http.HttpServlet</b>
+ *
+ * @author David VIttor
+ * @date 15/09/14
+ * @since 2.10.2-svn7
+ */
+public class WikiAjaxDispatcherServlet extends HttpServlet {
+    private static ServiceRegistry m_serviceRegistry;
+    static final Logger log = Logger.getLogger(WikiAjaxDispatcherServlet.class.getName());
+    private static final String PATH_AJAX = "/ajax/";
+
+    public WikiAjaxDispatcherServlet() {
+        initServiceRegistry();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void init(ServletConfig config)
+            throws ServletException {
+        super.init(config);
+
+        initServiceRegistry();
+        log.info("WikiServlet initialized.");
+    }
+
+    /**
+     * Initialise the service registry to get classes of type HttpServlet
+     */
+    private static void initServiceRegistry() {
+        if (m_serviceRegistry == null) {
+            Collection<Class<?>> m_serviceClasses = new ArrayList<Class<?>>();
+            m_serviceClasses.add(HttpServlet.class);
+            m_serviceRegistry = new ServiceRegistry(m_serviceClasses.iterator());
+        }
+    }
+
+    public void register(HttpServlet servlet) {
+        initServiceRegistry();
+        m_serviceRegistry.registerServiceProvider(servlet,HttpServlet.class);
+    }
+
+    /**
+     * Calls {@link this.performAction}
+     */
+    public void doPost(HttpServletRequest req, HttpServletResponse res)
+            throws IOException, ServletException {
+        performAction(req,res);
+    }
+
+    /**
+     * Calls {@link this.performAction}
+     */
+    public void doGet(HttpServletRequest req, HttpServletResponse res)
+            throws IOException, ServletException {
+        performAction(req,res);
+    }
+
+    /**
+     * This is the main method which get the requestURI, gets the {@link this.getServletName} and
+     * finds a servlet using {@link this.findServletByName}. It the calls servlet.service().
+     * @param req the inbound request
+     * @param res the outbound response
+     * @throws IOException
+     * @throws ServletException if no registered servlet can be found
+     */
+    private void performAction(HttpServletRequest req, HttpServletResponse res)
+            throws IOException, ServletException {
+        String path = req.getRequestURI();
+        String servletName = getServletName(path);
+        if (servletName!=null) {
+            HttpServlet foundServlet = findServletByName(servletName);
+            if (foundServlet != null) {
+                foundServlet.service(req, res);
+            } else {
+                log.error("No registered class for servletName=" + servletName + " in path=" + path);
+                throw new ServletException("No registered class for servletName=" + servletName);
+            }
+        }
+    }
+
+    /**
+     * Get the name of the servlet given the requestURI.
+     * @param path The requestURI, which must contains "/ajax/<ServletName>" in the path
+     * @return The ServletName for the requestURI, or null
+     * @throws ServletException if the path is invalid
+     */
+    public String getServletName(String path) throws ServletException {
+        String result = null;
+        if (StringUtils.isBlank(path)) {
+            return result;
+        }
+        int index = path.indexOf(PATH_AJAX);
+        if (index<0) {
+            throw new ServletException("Invalid path provided " + path + " does not contain '" + PATH_AJAX + "'");
+        }
+        path = path.substring(index+6);
+        index = path.indexOf("/");
+        if (index == -1) {
+            index = path.indexOf("#");
+            if (index == -1) {
+                index = path.indexOf("?");
+            }
+        }
+        if (index == -1) {
+            result = path;
+        }
+        else {
+            result = path.substring(0,index);
+        }
+
+        return result;
+    }
+
+    /**
+     * Find the servlet as registered in the serviceRegistry.
+     *
+     * <b>Note:</b> Currently there is an issue if there are two servlets with the same name,
+     * but different packages. Only the first one found will be returned.
+     * However with Servlets 3.0 hopefully, the annotation
+     * <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebServlet.html">@WebServlet</a>
+     * will obselete all this code anyway.
+     * @param servletName the name of the servlet from {@link this.getServletNamee}
+     * @return The first servlet found, or null.
+     */
+    public HttpServlet findServletByName(String servletName) {
+        Iterator<HttpServlet> itr = m_serviceRegistry.getServiceProviders(HttpServlet.class, false);
+        HttpServlet foundServlet = null;
+        while (itr.hasNext()) {
+            HttpServlet servlet = itr.next();
+            if (servlet.getClass().getSimpleName().equals(servletName)) {
+                foundServlet = servlet;
+                break;
+            }
+        }
+        if (foundServlet == null) {
+            try {
+                Iterator<HttpServlet> itr2 = m_serviceRegistry.lookupProviders(HttpServlet.class);
+                while (itr2.hasNext()) {
+                    HttpServlet servlet = itr2.next();
+                    if (servlet.getClass().getSimpleName().equals(servletName)) {
+                        foundServlet = servlet;
+                        break;
+                    }
+                }
+            } catch (Throwable e) {
+                log.error(e,e);
+            }
+        }
+        return foundServlet;
+    }
+
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/plugin/SampleAjaxPlugin.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/plugin/SampleAjaxPlugin.java	(revision 0)
+++ jspwiki-war/src/main/java/org/apache/wiki/plugin/SampleAjaxPlugin.java	(working copy)
@@ -0,0 +1,63 @@
+/*
+    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.wiki.plugin;
+
+import org.apache.wiki.WikiContext;
+import org.apache.wiki.api.exceptions.PluginException;
+import org.apache.wiki.api.plugin.WikiPlugin;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author David VIttor
+ * @date 15/09/14
+ * @since 2.10.2-svn7
+ */
+public class SampleAjaxPlugin extends HttpServlet implements WikiPlugin {
+    @Override
+    public String execute(WikiContext context, Map<String, String> params) throws PluginException {
+        String baseUrl = context.getEngine().getBaseURL();
+        String url = baseUrl+"ajax/SampleAjaxPlugin";
+        String html= "<div onclick='makeRequest(\"GET\",\""+url+"\",\"result\",\"Loading...\")' style='color: blue; cursor: pointer'>Press Me</div>\n"+
+                        "<div id='result'></div>";
+        return html;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        try {
+            Thread.sleep(5000); // Wait 5 seconds
+        } catch (Exception e) {}
+        resp.getWriter().print("You called by get!");
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        try {
+            Thread.sleep(5000); // Wait 5 seconds
+        } catch (Exception e) {}
+        resp.getWriter().print("You called by post!");
+    }
+}
Index: jspwiki-war/src/main/java/org/apache/wiki/rpc/json/JSONRPCManager.java
===================================================================
--- jspwiki-war/src/main/java/org/apache/wiki/rpc/json/JSONRPCManager.java	(revision 1622810)
+++ jspwiki-war/src/main/java/org/apache/wiki/rpc/json/JSONRPCManager.java	(working copy)
@@ -147,7 +147,7 @@
         
         getBridge(context).registerObject(id, c);
         requestJSON(context);
-        
+
         return id;
     }
 
@@ -157,7 +157,7 @@
      * @param context The WikiContext.
      */
     public static void requestJSON(WikiContext context) {
-    
+
         /* Deprecated.
            All json stuff is in jspwiki-common.js; not need to inject jsonrpc.js
         TemplateManager.addResourceRequest(context,
@@ -210,18 +210,19 @@
 
                 WikiEngine e = WikiEngine.getInstance(req.getSession().getServletContext(), null);
 
+                boolean global = false;
                 for (Iterator i = c_globalObjects.values().iterator(); i.hasNext(); ) {
                     CallbackContainer cc = (CallbackContainer) i.next();
 
                     if (cc.m_object == instance) {
+                        global = true;
                         canDo = e.getAuthorizationManager().checkPermission(WikiSession.getWikiSession(e, req),
                                 cc.m_permission);
-
                         break;
                     }
                 }
 
-                if (canDo) {
+                if ((global && canDo) || !global) {
                     return;
                 }
             }
Index: jspwiki-war/src/main/resources/META-INF/services/javax.servlet.http.HttpServlet
===================================================================
--- jspwiki-war/src/main/resources/META-INF/services/javax.servlet.http.HttpServlet	(revision 0)
+++ jspwiki-war/src/main/resources/META-INF/services/javax.servlet.http.HttpServlet	(working copy)
@@ -0,0 +1 @@
+org.apache.wiki.plugin.SampleAjaxPlugin
\ No newline at end of file
Index: jspwiki-war/src/main/scripts/jspwiki-common.js
===================================================================
--- jspwiki-war/src/main/scripts/jspwiki-common.js	(revision 1622810)
+++ jspwiki-war/src/main/scripts/jspwiki-common.js	(working copy)
@@ -219,7 +219,67 @@
 	}
 }
 
+/** AJAX Requests as per http://javapapers.com/ajax/getting-started-with-ajax-using-java/ **/
+/*
+ * creates a new XMLHttpRequest object which is the backbone of AJAX,
+ * or returns false if the browser doesn't support it
+ */
+function getXMLHttpRequest() {
+	var xmlHttpReq = false;
+	// to create XMLHttpRequest object in non-Microsoft browsers
+	if (window.XMLHttpRequest) {
+		xmlHttpReq = new XMLHttpRequest();
+	} else if (window.ActiveXObject) {
+		try {
+			// to create XMLHttpRequest object in later versions
+			// of Internet Explorer
+			xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
+		} catch (exp1) {
+			try {
+				// to create XMLHttpRequest object in older versions
+				// of Internet Explorer
+				xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
+			} catch (exp2) {
+				xmlHttpReq = false;
+			}
+		}
+	}
+	return xmlHttpReq;
+}
 
+/*
+ * AJAX call starts with this function
+ */
+function makeRequest(method,url,responseId,loading) {
+	var xmlHttpRequest = getXMLHttpRequest();
+	xmlHttpRequest.onreadystatechange = getReadyStateHandler(xmlHttpRequest,responseId,loading);
+	xmlHttpRequest.open(method, url, true);
+	xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+	xmlHttpRequest.send(null);
+}
+
+/*
+ * Returns a function that waits for the state change in XMLHttpRequest
+ */
+function getReadyStateHandler(xmlHttpRequest,responseId,loading) {
+	// an anonymous function returned
+	// it listens to the XMLHttpRequest instance
+	return function() {
+		if (xmlHttpRequest.readyState >=1 && xmlHttpRequest.readyState <4) {
+			document.getElementById(responseId).innerHTML = loading;
+		}
+		if (xmlHttpRequest.readyState == 4) {
+			if (xmlHttpRequest.status == 200) {
+				document.getElementById(responseId).innerHTML = xmlHttpRequest.responseText;
+			} else {
+				document.getElementById(responseId).innerHTML("HTTP error " + xmlHttpRequest.status + ": " + xmlHttpRequest.statusText);
+			}
+		}
+	};
+}
+/** End AJAX Requests **/
+
+
 /** 100 Wiki functions **/
 var Wiki = {
 
@@ -414,6 +474,12 @@
 
 	$jsonid : 10000,
 	jsonrpc: function(method, params, fn) {
+		$$('meta').each(function(el){
+			var n = el.getProperty('name') || '';
+			if( n.indexOf('wiki') == 0 ) this[n.substr(4)] = el.getProperty('content');
+		},this);
+
+		if (Wiki.JsonUrl) {
 		new Ajax( Wiki.JsonUrl, {
 			postBody: Json.toString({"id":Wiki.$jsonid++, "method":method, "params":params}),
 			method: 'post',
@@ -425,6 +491,7 @@
 				}
 			}
 		}).request();
+		}
 	}
 }
 
Index: jspwiki-war/src/main/scripts/wiki/Wiki.js
===================================================================
--- jspwiki-war/src/main/scripts/wiki/Wiki.js	(revision 1622810)
+++ jspwiki-war/src/main/scripts/wiki/Wiki.js	(working copy)
@@ -437,9 +437,12 @@
     */
     jsonid : 1e4, //seed
     jsonrpc: function(method, params, callback){
+		$$('meta').each(function(el){
+			var n = el.getProperty('name') || '';
+			if( n.indexOf('wiki') == 0 ) this[n.substr(4)] = el.getProperty('content');
+		},this);
 
-        if(this.JsonUrl){
-
+		if (this.JsonUrl) {
             new Request.JSON({
                 url: this.JsonUrl,
                 data: JSON.encode({ 
@@ -458,7 +461,6 @@
                     callback(null);
                 }
             }).send();
-
         }
     }
 
Index: jspwiki-war/src/main/webapp/WEB-INF/web.xml
===================================================================
--- jspwiki-war/src/main/webapp/WEB-INF/web.xml	(revision 1622810)
+++ jspwiki-war/src/main/webapp/WEB-INF/web.xml	(working copy)
@@ -141,6 +141,13 @@
        <load-on-startup>1</load-on-startup>
    </servlet>
 
+    <!-- WikiAjaxDispatcherServlet -->
+    <servlet>
+        <servlet-name>WikiAjaxDispatcherServlet</servlet-name>
+        <servlet-class>org.apache.wiki.WikiAjaxDispatcherServlet</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
    <!--
        Attachment exchange handler.
      -->
@@ -159,7 +166,12 @@
        <servlet-name>WikiServlet</servlet-name>
        <url-pattern>/wiki/*</url-pattern>
    </servlet-mapping>
-   
+
+    <servlet-mapping>
+        <servlet-name>WikiAjaxDispatcherServlet</servlet-name>
+        <url-pattern>/ajax/*</url-pattern>
+    </servlet-mapping>
+
    <servlet-mapping>
        <servlet-name>com.metaparadigm.jsonrpc.JSONRPCServlet</servlet-name>
        <url-pattern>/JSON-RPC</url-pattern>
Index: jspwiki-war/src/test/java/org/apache/wiki/WikiAjaxServletTest.java
===================================================================
--- jspwiki-war/src/test/java/org/apache/wiki/WikiAjaxServletTest.java	(revision 0)
+++ jspwiki-war/src/test/java/org/apache/wiki/WikiAjaxServletTest.java	(working copy)
@@ -0,0 +1,68 @@
+/*
+    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.wiki;
+
+import junit.framework.TestCase;
+
+import org.apache.wiki.plugin.SampleAjaxPlugin;
+import org.apache.wiki.xmlrpc.RPCServlet;
+
+import javax.servlet.http.HttpServlet;
+
+/**
+ * @author David VIttor
+ * @date 15/09/14
+ * @since 2.10.2-svn7
+ */
+public class WikiAjaxServletTest extends TestCase {
+
+    public void testServlets() throws Exception {
+        String[] paths = new String[] {
+                "/ajax/MyPlugin",
+                "/ajax/MyPlugin/",
+                "/ajax/MyPlugin/Friend",
+                "/ajax/MyPlugin?",
+                "/ajax/MyPlugin?param=123&param=231",
+                "/ajax/MyPlugin#hashCode?param=123&param=231",
+                "http://google.com.au/test/ajax/MyPlugin#hashCode?param=123&param=231",
+                "/test//ajax/MyPlugin#hashCode?param=123&param=231",
+                "http://localhost:8080/ajax/MyPlugin#hashCode?param=123&param=231" };
+
+        assertEquals(9,paths.length);
+        WikiAjaxDispatcherServlet wikiAjaxDispatcherServlet = new WikiAjaxDispatcherServlet();
+        for (String path : paths) {
+            String servletName = wikiAjaxDispatcherServlet.getServletName(path);
+            assertEquals("MyPlugin", servletName);
+        }
+
+        // The plugin SampleAjaxPlugin is automatically registered from the META-INF/services
+        HttpServlet servlet = wikiAjaxDispatcherServlet.findServletByName("SampleAjaxPlugin");
+        assertNotNull(servlet);
+        assertTrue(servlet instanceof SampleAjaxPlugin);
+
+        wikiAjaxDispatcherServlet.register(new RPCServlet());
+        HttpServlet servlet2 = wikiAjaxDispatcherServlet.findServletByName("RPCServlet");
+        assertNotNull(servlet2);
+        assertTrue(servlet2 instanceof RPCServlet);
+
+        HttpServlet servlet3 = wikiAjaxDispatcherServlet.findServletByName("TestWikiNonAjaxServlet");
+        assertNull(servlet3);
+    }
+
+}
Index: jspwiki-war/src/test/resources/META-INF/services/org.apache.wiki.WikiAjaxServlet
===================================================================
--- jspwiki-war/src/test/resources/META-INF/services/org.apache.wiki.WikiAjaxServlet	(revision 0)
+++ jspwiki-war/src/test/resources/META-INF/services/org.apache.wiki.WikiAjaxServlet	(working copy)
@@ -0,0 +1 @@
+org.apache.wiki.ajax.TestWikiAjaxServlet
\ No newline at end of file
