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 */
019 package org.apache.wiki.xmlrpc;
020
021 import java.io.IOException;
022 import java.io.OutputStream;
023 import java.io.OutputStreamWriter;
024 import java.io.PrintWriter;
025 import java.util.Vector;
026
027 import javax.servlet.ServletConfig;
028 import javax.servlet.ServletException;
029 import javax.servlet.http.HttpServlet;
030 import javax.servlet.http.HttpServletRequest;
031 import javax.servlet.http.HttpServletResponse;
032
033 import org.apache.log4j.Logger;
034 import org.apache.xmlrpc.*;
035
036 import org.apache.wiki.WikiContext;
037 import org.apache.wiki.WikiEngine;
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 */
050 public 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 }