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 private WikiEngine m_engine; 056 057 /** 058 * {@inheritDoc} 059 * 060 * This sets the AjaxPath to "/ajax/" as configured in "jspwiki.ajax.url.prefix". 061 * Note: Do not change this without also changing the web.xml file. 062 */ 063 @Override 064 public void init(ServletConfig config) 065 throws ServletException { 066 super.init(config); 067 m_engine = WikiEngine.getInstance(config); 068 PATH_AJAX = "/"+TextUtil.getStringProperty(m_engine.getWikiProperties(), "jspwiki.ajax.url.prefix", "ajax")+"/"; 069 log.info("WikiAjaxDispatcherServlet initialized."); 070 } 071 072 /** 073 * Register a {@link WikiAjaxServlet} using the servlet mapping as the alias 074 */ 075 public static void registerServlet(WikiAjaxServlet servlet) { 076 registerServlet(servlet.getServletMapping(),servlet); 077 } 078 079 /** 080 * Register a {@link WikiAjaxServlet} with a specific alias, and default permission {@link PagePermission#VIEW}. 081 */ 082 public static void registerServlet(String alias, WikiAjaxServlet servlet) { 083 registerServlet(alias, servlet, PagePermission.VIEW); 084 } 085 086 /** 087 * Regster a {@link WikiAjaxServlet} given an alias, the servlet, and the permission. 088 * This creates a temporary bundle object called {@link WikiAjaxDispatcherServlet.AjaxServletContainer} 089 * @param alias the uri link to this servlet 090 * @param servlet the servlet being registered 091 * @param perm the permission required to execute the servlet. 092 */ 093 public static void registerServlet(String alias, WikiAjaxServlet servlet, Permission perm) { 094 log.info("WikiAjaxDispatcherServlet registering "+alias+"="+servlet+" perm="+perm); 095 ajaxServlets.put(alias,new AjaxServletContainer(alias, servlet, perm)); 096 } 097 098 /** 099 * Calls {@link #performAction} 100 */ 101 @Override 102 public void doPost(HttpServletRequest req, HttpServletResponse res) 103 throws IOException, ServletException { 104 performAction(req,res); 105 } 106 107 /** 108 * Calls {@link #performAction} 109 */ 110 @Override 111 public void doGet(HttpServletRequest req, HttpServletResponse res) 112 throws IOException, ServletException { 113 performAction(req,res); 114 } 115 116 /** 117 * The main method which get the requestURI "/ajax/<ServletName>", gets the 118 * {@link #getServletName} and finds the servlet using {@link #findServletByName}. 119 * It then calls {@link WikiAjaxServlet#service} method. 120 * @param req the inbound request 121 * @param res the outbound response 122 * @throws IOException 123 * @throws ServletException if no registered servlet can be found 124 */ 125 private void performAction(HttpServletRequest req, HttpServletResponse res) 126 throws IOException, ServletException { 127 final String path = req.getRequestURI(); 128 final String servletName = getServletName(path); 129 if (servletName!=null) { 130 final AjaxServletContainer container = findServletContainer(servletName); 131 if (container != null) { 132 final WikiAjaxServlet servlet = container.servlet; 133 if ( validatePermission(req,container) ) { 134 req.setCharacterEncoding(m_engine.getContentEncoding()); 135 res.setCharacterEncoding(m_engine.getContentEncoding()); 136 final String actionName = AjaxUtil.getNextPathPart(req.getRequestURI(), servlet.getServletMapping()); 137 log.debug("actionName="+actionName); 138 final Object params = req.getParameter("params"); 139 log.debug("params="+params); 140 List<String> paramValues = new ArrayList<String>(); 141 if (params instanceof String) { 142 final String paramString = (String)params; 143 if (StringUtils.isNotBlank(paramString)) { 144 paramValues = Arrays.asList(paramString.trim().split(",")); 145 } 146 } 147 servlet.service(req, res, actionName, paramValues); 148 } else { 149 log.warn("Servlet container "+container+" not authorised. Permission required."); 150 } 151 } else { 152 log.error("No registered class for servletName=" + servletName + " in path=" + path); 153 throw new ServletException("No registered class for servletName=" + servletName); 154 } 155 } 156 } 157 158 /** 159 * Validate the permission of the {@link WikiAjaxServlet} using the {@link AuthorizationManager#checkPermission} 160 * 161 * @param req the servlet request 162 * @param container the container info of the servlet 163 * @return true if permission is valid 164 */ 165 private boolean validatePermission(HttpServletRequest req, AjaxServletContainer container) { 166 final WikiEngine e = WikiEngine.getInstance(req.getSession().getServletContext(), null); 167 boolean valid = false; 168 if (container != null) { 169 valid = e.getAuthorizationManager().checkPermission(WikiSession.getWikiSession(e, req), container.permission); 170 } 171 return valid; 172 } 173 174 /** 175 * Get the ServletName from the requestURI "/ajax/<ServletName>", using {@link AjaxUtil#getNextPathPart}. 176 * 177 * @param path The requestURI, which must contains "/ajax/<ServletName>" in the path 178 * @return The ServletName for the requestURI, or null 179 * @throws ServletException if the path is invalid 180 */ 181 public String getServletName(String path) throws ServletException { 182 return AjaxUtil.getNextPathPart(path, PATH_AJAX); 183 } 184 185 /** 186 * Find the {@link AjaxServletContainer} as registered in {@link #registerServlet}. 187 * 188 * @param servletName the name of the servlet from {@link #getServletName} 189 * @return The first servlet found, or null. 190 */ 191 private AjaxServletContainer findServletContainer(String servletAlias) { 192 return ajaxServlets.get(servletAlias); 193 } 194 195 /** 196 * Find the {@link WikiAjaxServlet} given the servletAlias that it was registered with. 197 * 198 * @param servletAlias the value provided to {@link #registerServlet} 199 * @return the {@link WikiAjaxServlet} given the servletAlias that it was registered with. 200 */ 201 public WikiAjaxServlet findServletByName(String servletAlias) { 202 final AjaxServletContainer container = ajaxServlets.get(servletAlias); 203 if (container != null) { 204 return container.servlet; 205 } 206 return null; 207 } 208 209 private static class AjaxServletContainer { 210 String alias; 211 WikiAjaxServlet servlet; 212 Permission permission; 213 214 public AjaxServletContainer(String alias, WikiAjaxServlet servlet, Permission permission) { 215 this.alias = alias; 216 this.servlet = servlet; 217 this.permission = permission; 218 } 219 220 @Override 221 public String toString() { 222 return getClass().getSimpleName()+" "+alias+"="+servlet.getClass().getSimpleName()+" permission="+permission; 223 } 224 } 225 226}