001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.xmlrpc;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.servlet.ServletResponseUtil;
020    import com.liferay.portal.kernel.util.ContentTypes;
021    import com.liferay.portal.kernel.util.HttpUtil;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Tuple;
025    import com.liferay.portal.kernel.xmlrpc.Method;
026    import com.liferay.portal.kernel.xmlrpc.Response;
027    import com.liferay.portal.kernel.xmlrpc.XmlRpcConstants;
028    import com.liferay.portal.kernel.xmlrpc.XmlRpcException;
029    import com.liferay.portal.kernel.xmlrpc.XmlRpcUtil;
030    import com.liferay.portal.util.PortalInstances;
031    
032    import java.io.IOException;
033    import java.io.InputStream;
034    
035    import java.util.HashMap;
036    import java.util.Map;
037    
038    import javax.servlet.http.HttpServlet;
039    import javax.servlet.http.HttpServletRequest;
040    import javax.servlet.http.HttpServletResponse;
041    
042    /**
043     * @author Alexander Chow
044     * @author Brian Wing Shun Chan
045     */
046    public class XmlRpcServlet extends HttpServlet {
047    
048            public static void registerMethod(Method method) {
049                    if (method == null) {
050                            return;
051                    }
052    
053                    String token = method.getToken();
054                    String methodName = method.getMethodName();
055    
056                    Map<String, Method> tokenMethods = _methodRegistry.get(token);
057    
058                    if (tokenMethods == null) {
059                            tokenMethods = new HashMap<String, Method>();
060    
061                            _methodRegistry.put(token, tokenMethods);
062                    }
063    
064                    Method registeredMethod = tokenMethods.get(methodName);
065    
066                    if (registeredMethod != null) {
067                            if (_log.isWarnEnabled()) {
068                                    _log.warn(
069                                            "There is already an XML-RPC method registered with name " +
070                                                    methodName + " at " + token);
071                            }
072                    }
073                    else {
074                            tokenMethods.put(methodName, method);
075                    }
076            }
077    
078            public static void unregisterMethod(Method method) {
079                    if (method == null) {
080                            return;
081                    }
082    
083                    String token = method.getToken();
084                    String methodName = method.getMethodName();
085    
086                    Map<String, Method> tokenMethods = _methodRegistry.get(token);
087    
088                    if (tokenMethods == null) {
089                            return;
090                    }
091    
092                    tokenMethods.remove(methodName);
093    
094                    if (tokenMethods.isEmpty()) {
095                            _methodRegistry.remove(token);
096                    }
097            }
098    
099            @Override
100            protected void doPost(
101                    HttpServletRequest request, HttpServletResponse response) {
102    
103                    Response xmlRpcResponse = null;
104    
105                    try {
106                            long companyId = PortalInstances.getCompanyId(request);
107    
108                            String token = getToken(request);
109    
110                            InputStream is = request.getInputStream();
111    
112                            String xml = StringUtil.read(is);
113    
114                            Tuple methodTuple = XmlRpcParser.parseMethod(xml);
115    
116                            String methodName = (String)methodTuple.getObject(0);
117                            Object[] args = (Object[])methodTuple.getObject(1);
118    
119                            xmlRpcResponse = invokeMethod(companyId, token, methodName, args);
120                    }
121                    catch (IOException ioe) {
122                            xmlRpcResponse = XmlRpcUtil.createFault(
123                                    XmlRpcConstants.NOT_WELL_FORMED, "XML is not well formed");
124    
125                            if (_log.isDebugEnabled()) {
126                                    _log.debug(ioe, ioe);
127                            }
128                    }
129                    catch (XmlRpcException xmlrpce) {
130                            _log.error(xmlrpce, xmlrpce);
131                    }
132    
133                    if (xmlRpcResponse == null) {
134                            xmlRpcResponse = XmlRpcUtil.createFault(
135                                    XmlRpcConstants.SYSTEM_ERROR, "Unknown error occurred");
136                    }
137    
138                    response.setCharacterEncoding(StringPool.UTF8);
139                    response.setContentType(ContentTypes.TEXT_XML);
140                    response.setStatus(HttpServletResponse.SC_OK);
141    
142                    try {
143                            ServletResponseUtil.write(response, xmlRpcResponse.toXml());
144                    }
145                    catch (Exception e) {
146                            if (_log.isWarnEnabled()) {
147                                    _log.warn(e, e);
148                            }
149    
150                            response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
151                    }
152            }
153    
154            protected Method getMethod(String token, String methodName) {
155                    Method method = null;
156    
157                    Map<String, Method> tokenMethods = _methodRegistry.get(token);
158    
159                    if (tokenMethods != null) {
160                            method = tokenMethods.get(methodName);
161                    }
162    
163                    return method;
164            }
165    
166            protected String getToken(HttpServletRequest request) {
167                    String token = request.getPathInfo();
168    
169                    return HttpUtil.fixPath(token);
170            }
171    
172            protected Response invokeMethod(
173                            long companyId, String token, String methodName, Object[] arguments)
174                    throws XmlRpcException {
175    
176                    Method method = getMethod(token, methodName);
177    
178                    if (method == null) {
179                            return XmlRpcUtil.createFault(
180                                    XmlRpcConstants.REQUESTED_METHOD_NOT_FOUND,
181                                    "Requested method not found");
182                    }
183    
184                    if (!method.setArguments(arguments)) {
185                            return XmlRpcUtil.createFault(
186                                    XmlRpcConstants.INVALID_METHOD_PARAMETERS,
187                                    "Method arguments are invalid");
188                    }
189    
190                    return method.execute(companyId);
191            }
192    
193            private static Log _log = LogFactoryUtil.getLog(XmlRpcServlet.class);
194    
195            private static Map<String, Map<String, Method>> _methodRegistry =
196                    new HashMap<String, Map<String, Method>>();
197    
198    }