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.wiki.WikiContext; 035import org.apache.wiki.WikiEngine; 036import org.apache.xmlrpc.ContextXmlRpcHandler; 037import org.apache.xmlrpc.Invoker; 038import org.apache.xmlrpc.XmlRpcContext; 039import org.apache.xmlrpc.XmlRpcHandlerMapping; 040import org.apache.xmlrpc.XmlRpcServer; 041 042/** 043 * Handles all incoming servlet requests for XML-RPC calls. 044 * <P> 045 * Uses two initialization parameters: 046 * <UL> 047 * <LI><B>handler</B> : the class which is used to handle the RPC calls. 048 * <LI><B>prefix</B> : The command prefix for that particular handler. 049 * </UL> 050 * 051 * @since 1.6.6 052 */ 053public class RPCServlet extends HttpServlet 054{ 055 private static final long serialVersionUID = 3976735878410416180L; 056 057 /** This is what is appended to each command, if the handler has 058 not been specified. */ 059 // FIXME: Should this be $default? 060 public static final String XMLRPC_PREFIX = "wiki"; 061 062 private WikiEngine m_engine; 063 private XmlRpcServer m_xmlrpcServer = new XmlRpcServer(); 064 065 static Logger log = Logger.getLogger( RPCServlet.class ); 066 067 public void initHandler( String prefix, String handlerName ) 068 throws ClassNotFoundException, 069 InstantiationException, 070 IllegalAccessException 071 { 072 /* 073 Class handlerClass = Class.forName( handlerName ); 074 WikiRPCHandler rpchandler = (WikiRPCHandler) handlerClass.newInstance(); 075 rpchandler.initialize( m_engine ); 076 m_xmlrpcServer.addHandler( prefix, rpchandler ); 077 */ 078 Class< ? > handlerClass = Class.forName( handlerName ); 079 m_xmlrpcServer.addHandler( prefix, new LocalHandler(handlerClass) ); 080 } 081 082 /** 083 * Initializes the servlet. 084 */ 085 public void init( ServletConfig config ) 086 throws ServletException 087 { 088 m_engine = WikiEngine.getInstance( config ); 089 090 String handlerName = config.getInitParameter( "handler" ); 091 String prefix = config.getInitParameter( "prefix" ); 092 093 if( handlerName == null ) handlerName = "org.apache.wiki.xmlrpc.RPCHandler"; 094 if( prefix == null ) prefix = XMLRPC_PREFIX; 095 096 try 097 { 098 initHandler( prefix, handlerName ); 099 100 // 101 // FIXME: The metaweblog API should be possible to turn off. 102 // 103 initHandler( "metaWeblog", 104 "org.apache.wiki.xmlrpc.MetaWeblogHandler" ); 105 } 106 catch( Exception e ) 107 { 108 log.fatal("Unable to start RPC interface: ", e); 109 throw new ServletException( "No RPC interface", e ); 110 } 111 } 112 113 /** 114 * Handle HTTP POST. This is an XML-RPC call, and we'll just forward 115 * the query to an XmlRpcServer. 116 */ 117 public void doPost( HttpServletRequest request, HttpServletResponse response ) 118 throws ServletException 119 { 120 log.debug("Received POST to RPCServlet"); 121 122 try 123 { 124 WikiContext ctx = m_engine.createContext( request, WikiContext.NONE ); 125 126 XmlRpcContext xmlrpcContext = new WikiXmlRpcContext( m_xmlrpcServer.getHandlerMapping(), 127 ctx ); 128 129 byte[] result = m_xmlrpcServer.execute( request.getInputStream(), xmlrpcContext ); 130 131 // 132 // I think it's safe to write the output as UTF-8: 133 // The XML-RPC standard never creates other than USASCII 134 // (which is UTF-8 compatible), and our special UTF-8 135 // hack just creates UTF-8. So in all cases our butt 136 // should be covered. 137 // 138 response.setContentType( "text/xml; charset=utf-8" ); 139 response.setContentLength( result.length ); 140 141 OutputStream out = response.getOutputStream(); 142 out.write( result ); 143 out.flush(); 144 145 // log.debug("Result = "+new String(result) ); 146 } 147 catch( IOException e ) 148 { 149 throw new ServletException("Failed to build RPC result", e); 150 } 151 } 152 153 /** 154 * Handles HTTP GET. However, we do not respond to GET requests, 155 * other than to show an explanatory text. 156 */ 157 public void doGet( HttpServletRequest request, HttpServletResponse response ) 158 throws ServletException 159 { 160 log.debug("Received HTTP GET to RPCServlet"); 161 162 try 163 { 164 String msg = "We do not support HTTP GET here. Sorry."; 165 response.setContentType( "text/plain" ); 166 response.setContentLength( msg.length() ); 167 168 PrintWriter writer = new PrintWriter( new OutputStreamWriter( response.getOutputStream() ) ); 169 170 writer.println( msg ); 171 writer.flush(); 172 } 173 catch( IOException e ) 174 { 175 throw new ServletException("Failed to build RPC result", e); 176 } 177 } 178 179 private static class LocalHandler 180 implements ContextXmlRpcHandler 181 { 182 private Class< ? > m_clazz; 183 184 public LocalHandler( Class< ? > clazz ) 185 { 186 m_clazz = clazz; 187 } 188 189 public Object execute(String method, Vector params, XmlRpcContext context) throws Exception 190 { 191 WikiRPCHandler rpchandler = (WikiRPCHandler) m_clazz.newInstance(); 192 rpchandler.initialize( ((WikiXmlRpcContext)context).getWikiContext() ); 193 194 Invoker invoker = new Invoker( rpchandler ); 195 196 return invoker.execute( method, params ); 197 } 198 } 199 200 private static class WikiXmlRpcContext 201 implements XmlRpcContext 202 { 203 private XmlRpcHandlerMapping m_mapping; 204 private WikiContext m_context; 205 206 public WikiXmlRpcContext( XmlRpcHandlerMapping map, WikiContext ctx ) 207 { 208 m_mapping = map; 209 m_context = ctx; 210 } 211 212 public XmlRpcHandlerMapping getHandlerMapping() 213 { 214 return m_mapping; 215 } 216 217 public String getPassword() 218 { 219 // TODO Auto-generated method stub 220 return null; 221 } 222 223 public String getUserName() 224 { 225 // TODO Auto-generated method stub 226 return null; 227 } 228 229 public WikiContext getWikiContext() 230 { 231 return m_context; 232 } 233 } 234}