001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.xmlrpc; 020 021import java.io.IOException; 022import java.io.OutputStream; 023import java.io.OutputStreamWriter; 024import java.io.PrintWriter; 025import java.util.Vector; 026 027import javax.servlet.ServletConfig; 028import javax.servlet.ServletException; 029import javax.servlet.http.HttpServlet; 030import javax.servlet.http.HttpServletRequest; 031import javax.servlet.http.HttpServletResponse; 032 033import org.apache.log4j.Logger; 034import org.apache.xmlrpc.*; 035import org.apache.wiki.WikiContext; 036import org.apache.wiki.WikiEngine; 037import org.apache.wiki.ajax.WikiAjaxDispatcherServlet; 038 039/** 040 * Handles all incoming servlet requests for XML-RPC calls. 041 * <P> 042 * Uses two initialization parameters: 043 * <UL> 044 * <LI><B>handler</B> : the class which is used to handle the RPC calls. 045 * <LI><B>prefix</B> : The command prefix for that particular handler. 046 * </UL> 047 * 048 * @since 1.6.6 049 */ 050public class RPCServlet extends HttpServlet 051{ 052 private static final long serialVersionUID = 3976735878410416180L; 053 054 /** This is what is appended to each command, if the handler has 055 not been specified. */ 056 // FIXME: Should this be $default? 057 public static final String XMLRPC_PREFIX = "wiki"; 058 059 private WikiEngine m_engine; 060 private XmlRpcServer m_xmlrpcServer = new XmlRpcServer(); 061 062 static Logger log = Logger.getLogger( RPCServlet.class ); 063 064 public void initHandler( String prefix, String handlerName ) 065 throws ClassNotFoundException, 066 InstantiationException, 067 IllegalAccessException 068 { 069 /* 070 Class handlerClass = Class.forName( handlerName ); 071 WikiRPCHandler rpchandler = (WikiRPCHandler) handlerClass.newInstance(); 072 rpchandler.initialize( m_engine ); 073 m_xmlrpcServer.addHandler( prefix, rpchandler ); 074 */ 075 Class handlerClass = Class.forName( handlerName ); 076 m_xmlrpcServer.addHandler( prefix, new LocalHandler(handlerClass) ); 077 } 078 079 /** 080 * Initializes the servlet. 081 */ 082 public void init( ServletConfig config ) 083 throws ServletException 084 { 085 m_engine = WikiEngine.getInstance( config ); 086 087 String handlerName = config.getInitParameter( "handler" ); 088 String prefix = config.getInitParameter( "prefix" ); 089 090 if( handlerName == null ) handlerName = "org.apache.wiki.xmlrpc.RPCHandler"; 091 if( prefix == null ) prefix = XMLRPC_PREFIX; 092 093 try 094 { 095 initHandler( prefix, handlerName ); 096 097 // 098 // FIXME: The metaweblog API should be possible to turn off. 099 // 100 initHandler( "metaWeblog", 101 "org.apache.wiki.xmlrpc.MetaWeblogHandler" ); 102 } 103 catch( Exception e ) 104 { 105 log.fatal("Unable to start RPC interface: ", e); 106 throw new ServletException( "No RPC interface", e ); 107 } 108 } 109 110 /** 111 * Handle HTTP POST. This is an XML-RPC call, and we'll just forward 112 * the query to an XmlRpcServer. 113 */ 114 public void doPost( HttpServletRequest request, HttpServletResponse response ) 115 throws ServletException 116 { 117 log.debug("Received POST to RPCServlet"); 118 119 try 120 { 121 WikiContext ctx = m_engine.createContext( request, WikiContext.NONE ); 122 123 XmlRpcContext xmlrpcContext = new WikiXmlRpcContext( m_xmlrpcServer.getHandlerMapping(), 124 ctx ); 125 126 byte[] result = m_xmlrpcServer.execute( request.getInputStream(), xmlrpcContext ); 127 128 // 129 // I think it's safe to write the output as UTF-8: 130 // The XML-RPC standard never creates other than USASCII 131 // (which is UTF-8 compatible), and our special UTF-8 132 // hack just creates UTF-8. So in all cases our butt 133 // should be covered. 134 // 135 response.setContentType( "text/xml; charset=utf-8" ); 136 response.setContentLength( result.length ); 137 138 OutputStream out = response.getOutputStream(); 139 out.write( result ); 140 out.flush(); 141 142 // log.debug("Result = "+new String(result) ); 143 } 144 catch( IOException e ) 145 { 146 throw new ServletException("Failed to build RPC result", e); 147 } 148 } 149 150 /** 151 * Handles HTTP GET. However, we do not respond to GET requests, 152 * other than to show an explanatory text. 153 */ 154 public void doGet( HttpServletRequest request, HttpServletResponse response ) 155 throws ServletException 156 { 157 log.debug("Received HTTP GET to RPCServlet"); 158 159 try 160 { 161 String msg = "We do not support HTTP GET here. Sorry."; 162 response.setContentType( "text/plain" ); 163 response.setContentLength( msg.length() ); 164 165 PrintWriter writer = new PrintWriter( new OutputStreamWriter( response.getOutputStream() ) ); 166 167 writer.println( msg ); 168 writer.flush(); 169 } 170 catch( IOException e ) 171 { 172 throw new ServletException("Failed to build RPC result", e); 173 } 174 } 175 176 private static class LocalHandler 177 implements ContextXmlRpcHandler 178 { 179 private Class m_clazz; 180 181 public LocalHandler( Class clazz ) 182 { 183 m_clazz = clazz; 184 } 185 186 public Object execute(String method, Vector params, XmlRpcContext context) throws Exception 187 { 188 WikiRPCHandler rpchandler = (WikiRPCHandler) m_clazz.newInstance(); 189 rpchandler.initialize( ((WikiXmlRpcContext)context).getWikiContext() ); 190 191 Invoker invoker = new Invoker( rpchandler ); 192 193 return invoker.execute( method, params ); 194 } 195 } 196 197 private static class WikiXmlRpcContext 198 implements XmlRpcContext 199 { 200 private XmlRpcHandlerMapping m_mapping; 201 private WikiContext m_context; 202 203 public WikiXmlRpcContext( XmlRpcHandlerMapping map, WikiContext ctx ) 204 { 205 m_mapping = map; 206 m_context = ctx; 207 } 208 209 public XmlRpcHandlerMapping getHandlerMapping() 210 { 211 return m_mapping; 212 } 213 214 public String getPassword() 215 { 216 // TODO Auto-generated method stub 217 return null; 218 } 219 220 public String getUserName() 221 { 222 // TODO Auto-generated method stub 223 return null; 224 } 225 226 public WikiContext getWikiContext() 227 { 228 return m_context; 229 } 230 } 231}