001/* 002 003 Licensed to the Apache Software Foundation (ASF) under one 004 or more contributor license agreements. See the NOTICE file 005 distributed with this work for additional information 006 regarding copyright ownership. The ASF licenses this file 007 to you under the Apache License, Version 2.0 (the 008 "License"); you may not use this file except in compliance 009 with the License. You may obtain a copy of the License at 010 011 http://www.apache.org/licenses/LICENSE-2.0 012 013 Unless required by applicable law or agreed to in writing, 014 software distributed under the License is distributed on an 015 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 KIND, either express or implied. See the License for the 017 specific language governing permissions and limitations 018 under the License. 019 */ 020package org.apache.wiki.ajax; 021 022import java.io.IOException; 023import java.security.Permission; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030import javax.servlet.ServletConfig; 031import javax.servlet.ServletException; 032import javax.servlet.http.HttpServlet; 033import javax.servlet.http.HttpServletRequest; 034import javax.servlet.http.HttpServletResponse; 035 036import org.apache.commons.lang.StringUtils; 037import org.apache.log4j.Logger; 038import org.apache.wiki.WikiEngine; 039import org.apache.wiki.WikiSession; 040import org.apache.wiki.auth.AuthorizationManager; 041import org.apache.wiki.auth.permissions.PagePermission; 042import org.apache.wiki.util.TextUtil; 043 044/** 045 * This provides a simple ajax servlet for handling /ajax/<ClassName> requests. 046 * HttpServlet classes need to be registered using {@link WikiAjaxDispatcherServlet.registerServlet(WikiAjaxServlet)} 047 * 048 * @since 2.10.2-svn12 049 */ 050public class WikiAjaxDispatcherServlet extends HttpServlet { 051 private static final long serialVersionUID = 1L; 052 private static Map<String,AjaxServletContainer> ajaxServlets = new HashMap<String,AjaxServletContainer>(); 053 static final Logger log = Logger.getLogger(WikiAjaxDispatcherServlet.class.getName()); 054 private String PATH_AJAX = "/ajax/"; 055 056 /** 057 * {@inheritDoc} 058 * 059 * This sets the AjaxPath to "/ajax/" as configured in "jspwiki.ajax.url.prefix". 060 * Note: Do not change this without also changing the web.xml file. 061 */ 062 public void init(ServletConfig config) 063 throws ServletException { 064 super.init(config); 065 WikiEngine e = WikiEngine.getInstance(config); 066 PATH_AJAX = "/"+TextUtil.getStringProperty(e.getWikiProperties(), "jspwiki.ajax.url.prefix", "ajax")+"/"; 067 log.info("WikiAjaxDispatcherServlet initialized."); 068 } 069 070 /** 071 * Register a {@link WikiAjaxServlet} using the servlet mapping as the alias 072 */ 073 public static void registerServlet(WikiAjaxServlet servlet) { 074 registerServlet(servlet.getServletMapping(),servlet); 075 } 076 077 /** 078 * Register a {@link WikiAjaxServlet} with a specific alias, and default permission {@link PagePermission.VIEW}. 079 */ 080 public static void registerServlet(String alias, WikiAjaxServlet servlet) { 081 registerServlet(alias, servlet, PagePermission.VIEW); 082 } 083 084 /** 085 * Regster a {@link WikiAjaxServlet} given an alias, the servlet, and the permission. 086 * Thie creates a temporary bundle object called {@link AjaxServletContainer} 087 * @param alias the uri link to this servlet 088 * @param servlet the servlet being registered 089 * @param perm the permission required to execute the servlet. 090 */ 091 public static void registerServlet(String alias, WikiAjaxServlet servlet, Permission perm) { 092 log.info("WikiAjaxDispatcherServlet registering "+alias+"="+servlet+" perm="+perm); 093 ajaxServlets.put(alias,new AjaxServletContainer(alias, servlet, perm)); 094 } 095 096 /** 097 * Calls {@link this.performAction} 098 */ 099 public void doPost(HttpServletRequest req, HttpServletResponse res) 100 throws IOException, ServletException { 101 performAction(req,res); 102 } 103 104 /** 105 * Calls {@link this.performAction} 106 */ 107 public void doGet(HttpServletRequest req, HttpServletResponse res) 108 throws IOException, ServletException { 109 performAction(req,res); 110 } 111 112 /** 113 * The main method which get the requestURI "/ajax/<ServletName>", gets the 114 * {@link this.getServletName} and finds the servlet using {@link this.findServletByName}. 115 * It then calls {@link WikiAjaxServlet.service} method. 116 * @param req the inbound request 117 * @param res the outbound response 118 * @throws IOException 119 * @throws ServletException if no registered servlet can be found 120 */ 121 private void performAction(HttpServletRequest req, HttpServletResponse res) 122 throws IOException, ServletException { 123 String path = req.getRequestURI(); 124 String servletName = getServletName(path); 125 if (servletName!=null) { 126 AjaxServletContainer container = findServletContainer(servletName); 127 if (container != null) { 128 WikiAjaxServlet servlet = container.servlet; 129 if ( validatePermission(req,container) ) { 130 String actionName = AjaxUtil.getNextPathPart(req.getRequestURI(), servlet.getServletMapping()); 131 log.debug("actionName="+actionName); 132 Object params = req.getParameter("params"); 133 log.debug("params="+params); 134 List<String> paramValues = new ArrayList<String>(); 135 if (params instanceof String) { 136 String paramString = (String)params; 137 if (StringUtils.isNotBlank(paramString)) { 138 paramValues = Arrays.asList(paramString.trim().split(",")); 139 } 140 } 141 servlet.service(req, res, actionName, paramValues); 142 } else { 143 log.warn("Servlet container "+container+" not authorised. Permission required."); 144 } 145 } else { 146 log.error("No registered class for servletName=" + servletName + " in path=" + path); 147 throw new ServletException("No registered class for servletName=" + servletName); 148 } 149 } 150 } 151 152 /** 153 * Validate the permission of the {@link WikiAjaxServlet} using the {@link AuthorizationManager.checkPermission} 154 * 155 * @param req the servlet request 156 * @param container the container info of the servlet 157 * @return true if permission is valid 158 */ 159 private boolean validatePermission(HttpServletRequest req, AjaxServletContainer container) { 160 WikiEngine e = WikiEngine.getInstance(req.getSession().getServletContext(), null); 161 boolean valid = false; 162 if (container != null) { 163 valid = e.getAuthorizationManager().checkPermission(WikiSession.getWikiSession(e, req), container.permission); 164 } 165 return valid; 166 } 167 168 /** 169 * Get the ServletName from the requestURI "/ajax/<ServletName>", using {@link AjaxUtil.getNextPathPath}. 170 * 171 * @param path The requestURI, which must contains "/ajax/<ServletName>" in the path 172 * @return The ServletName for the requestURI, or null 173 * @throws ServletException if the path is invalid 174 */ 175 public String getServletName(String path) throws ServletException { 176 return AjaxUtil.getNextPathPart(path, PATH_AJAX); 177 } 178 179 /** 180 * Find the {@link AjaxServletContainer} as registered in {@link WikiAjaxDispatcherServlet.registerServlet}. 181 * 182 * @param servletName the name of the servlet from {@link this.getServletName} 183 * @return The first servlet found, or null. 184 */ 185 private AjaxServletContainer findServletContainer(String servletAlias) { 186 return ajaxServlets.get(servletAlias); 187 } 188 189 /** 190 * Find the {@link WikiAjaxServlet} given the servletAlias that it was registered with. 191 * 192 * @param servletAlias the value provided to {@link this.registerServlet} 193 * @return 194 */ 195 public WikiAjaxServlet findServletByName(String servletAlias) { 196 AjaxServletContainer container = ajaxServlets.get(servletAlias); 197 if (container != null) { 198 return container.servlet; 199 } 200 return null; 201 } 202 203 private static class AjaxServletContainer { 204 String alias; 205 WikiAjaxServlet servlet; 206 Permission permission; 207 208 public AjaxServletContainer(String alias, WikiAjaxServlet servlet, Permission permission) { 209 this.alias = alias; 210 this.servlet = servlet; 211 this.permission = permission; 212 } 213 214 public String toString() { 215 return getClass().getSimpleName()+" "+alias+"="+servlet.getClass().getSimpleName()+" permission="+permission; 216 } 217 } 218 219}