Index: /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiUtils.java =================================================================== --- /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiUtils.java (revision 0) +++ /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiUtils.java (revision 0) @@ -0,0 +1,106 @@ +package com.xpn.xwiki.xmlrpc_new; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; + +import org.apache.xmlrpc.XmlRpcException; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.render.XWikiVelocityRenderer; +import com.xpn.xwiki.web.Utils; +import com.xpn.xwiki.web.XWikiRequest; +import com.xpn.xwiki.web.XWikiResponse; +import com.xpn.xwiki.web.XWikiServletContext; +import com.xpn.xwiki.web.XWikiURLFactory; + +/** + * This is an helper class containing some utility method for handling and setting up the XWiki and + * XMLRPC data objects needed to serve XMLRPC requests. + * + * @author fmancinelli + * + */ +public class XWikiUtils +{ + public static Object mock(Class someClass) + { + ClassLoader loader = someClass.getClassLoader(); + + InvocationHandler handler = new InvocationHandler() + { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + return null; + } + }; + Class[] interfaces = new Class[] {someClass}; + + return Proxy.newProxyInstance(loader, interfaces, handler); + } + + public static XWikiXmlRpcContext getXWikiXmlRpcContext(String token, XWikiRequest request, + XWikiResponse response, XWikiServletContext servletContext) throws XWikiException, + XmlRpcException + { + + XWikiContext context = getXWikiContext(request, response, servletContext); + XWikiXmlRpcUser user = XWikiUtils.checkToken(token, context); + com.xpn.xwiki.api.XWiki xwiki = new com.xpn.xwiki.api.XWiki(context.getWiki(), context); + + return new XWikiXmlRpcContext(context, context.getWiki(), xwiki, user); + } + + public static XWikiContext getXWikiContext(XWikiRequest request, XWikiResponse response, + XWikiServletContext servletContext) throws XWikiException + { + XWikiContext context = Utils.prepareContext("", request, response, servletContext); + XWiki xwiki = XWiki.getXWiki(context); + XWikiURLFactory urlf = + xwiki.getURLFactoryService().createURLFactory(context.getMode(), context); + context.setURLFactory(urlf); + XWikiVelocityRenderer.prepareContext(context); + + return context; + } + + public static Map getTokens(XWikiContext context) + { + Map tokens = (Map) context.getEngineContext().getAttribute("xmlrpc_tokens"); + if (tokens == null) { + tokens = new HashMap(); + context.getEngineContext().setAttribute("xmlrpc_tokens", tokens); + } + + return tokens; + } + + public static XWikiXmlRpcUser getUserForToken(XWikiContext context, String token) + { + return (XWikiXmlRpcUser) getTokens(context).get(token); + } + + public static XWikiXmlRpcUser checkToken(String token, XWikiContext context) + throws XmlRpcException + { + XWikiXmlRpcUser user = null; + String ip = context.getRequest().getRemoteAddr(); + + if (token != null) { + user = (XWikiXmlRpcUser) getTokens(context).get(token); + } + + if ((user == null) || (!user.getRemoteIp().equals(ip))) { + throw new XmlRpcException(String.format( + "[Access Denied: authentication token '%s' for IP %s is invalid]", token, ip)); + } + + context.setUser(user.getName()); + + return user; + } +} Index: /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcContext.java =================================================================== --- /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcContext.java (revision 0) +++ /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcContext.java (revision 0) @@ -0,0 +1,66 @@ +package com.xpn.xwiki.xmlrpc_new; + +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.api.XWiki; + +/** + * This is an helper class that contains information about the XWiki context and the current XMLRPC + * user. + * + * @author fmancinelli + * + */ +public class XWikiXmlRpcContext +{ + /* + * The XWiki API used by XMLRPC functions to perform operations + */ + private XWiki xwiki; + + /* + * The low-level XWiki API object. This is needed in some methods where the functionality cannot + * be completed by using the API wrapper (e.g., removing an attachment) + */ + private com.xpn.xwiki.XWiki baseXWiki; + + private XWikiXmlRpcUser user; + + /* + * This XWikiContext is needed for performing operations with the low-level API. + */ + private XWikiContext xwikiContext; + + public XWikiXmlRpcContext(XWikiContext xwikiContext, com.xpn.xwiki.XWiki baseXWiki, + XWiki xwiki, XWikiXmlRpcUser user) + { + this.xwikiContext = xwikiContext; + this.baseXWiki = baseXWiki; + this.xwiki = xwiki; + this.user = user; + } + + public XWiki getXWiki() + { + return xwiki; + } + + public XWikiXmlRpcUser getUser() + { + return user; + } + + public XWikiContext getXWikiContext() + { + return xwikiContext; + } + + public com.xpn.xwiki.XWiki getBaseXWiki() + { + return baseXWiki; + } + + public void setBaseXWiki(com.xpn.xwiki.XWiki baseXWiki) + { + this.baseXWiki = baseXWiki; + } +} Index: /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcHandler.java =================================================================== --- /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcHandler.java (revision 0) +++ /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcHandler.java (revision 0) @@ -0,0 +1,1401 @@ +package com.xpn.xwiki.xmlrpc_new; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.xmlrpc.XmlRpcException; +import org.suigeneris.jrcs.rcs.Version; +import org.xwiki.xmlrpc.Attachment; +import org.xwiki.xmlrpc.Comment; +import org.xwiki.xmlrpc.Page; +import org.xwiki.xmlrpc.PageHistorySummary; +import org.xwiki.xmlrpc.PageSummary; +import org.xwiki.xmlrpc.ServerInfo; +import org.xwiki.xmlrpc.Space; +import org.xwiki.xmlrpc.SpaceSummary; +import org.xwiki.xmlrpc.Utils; +import org.xwiki.xmlrpc.XWikiClass; +import org.xwiki.xmlrpc.XWikiClassSummary; +import org.xwiki.xmlrpc.XWikiObject; +import org.xwiki.xmlrpc.XWikiObjectSummary; +import org.xwiki.xmlrpc.XmlRpcConstants; + +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.api.Document; +import com.xpn.xwiki.api.Property; +import com.xpn.xwiki.api.PropertyClass; +import com.xpn.xwiki.api.XWiki; +import com.xpn.xwiki.doc.XWikiAttachment; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.web.XWikiRequest; +import com.xpn.xwiki.web.XWikiResponse; +import com.xpn.xwiki.web.XWikiServletContext; +import com.xpn.xwiki.web.XWikiServletRequest; + +/** + * The class containing the implementation of the XML-RPC API. Methods tagged with the ConfluenceAPI + * are compatible with Confluence. + * + * @author fmancinelli + * + */ +public class XWikiXmlRpcHandler +{ + private XWikiRequest xwikiRequest; + + private XWikiResponse xwikiResponse; + + private XWikiServletContext xwikiServletContext; + + private static final Log log = LogFactory.getLog(XWikiXmlRpcHandler.class); + + /** + * Initialize the XML-RPC handler with respect to the current HTTP request. + * + * @param servlet The servlet requesting the XML-RPC call handling. + * @param httpRequest The current HTTP request. + */ + public void init(HttpServlet servlet, HttpServletRequest httpRequest) + { + xwikiRequest = new XWikiServletRequest(httpRequest); + xwikiResponse = (XWikiResponse) XWikiUtils.mock(XWikiResponse.class); + ServletContext servletContext = servlet.getServletContext(); + xwikiServletContext = new XWikiServletContext(servletContext); + } + + /*********************************************************************************************** + * Authentication ****************************************************************************** + **********************************************************************************************/ + + /** + * Login + * + * @param userName + * @param password + * @return A token to be used in subsequent calls as an identification. + * @throws XWikiException + * @throws XmlRpcException If authentication fails. + * @category ConfluenceAPI + */ + public String login(String userName, String password) throws XWikiException, XmlRpcException + { + XWikiContext context = + XWikiUtils.getXWikiContext(xwikiRequest, xwikiResponse, xwikiServletContext); + com.xpn.xwiki.XWiki xwiki = context.getWiki(); + String token; + + if (xwiki.getAuthService().authenticate(userName, password, context) != null) { + // Generate "unique" token using a random number + token = xwiki.generateValidationKey(128); + String ip = context.getRequest().getRemoteAddr(); + + XWikiUtils.getTokens(context).put(token, + new XWikiXmlRpcUser(String.format("XWiki.%s", userName), ip)); + + return token; + } else { + throw new XmlRpcException(String.format("[Authentication failed for user %s.]", + userName)); + } + } + + /** + * Logout + * + * @param token The authentication token. + * @return True is logout was successful. + * @throws XWikiException + * @throws XmlRpcException An invalid token is provided. + * @category ConfluenceAPI + */ + public Boolean logout(String token) throws XWikiException, XmlRpcException + { + XWikiContext context = + XWikiUtils.getXWikiContext(xwikiRequest, xwikiResponse, xwikiServletContext); + XWikiUtils.checkToken(token, context); + + return XWikiUtils.getTokens(context).remove(token) != null; + } + + /*********************************************************************************************** + * Informaton ********************************************************************************** + **********************************************************************************************/ + + public Map getServerInfo(String token) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getServerInfo()", xwikiXmlRpcContext.getUser() + .getName())); + + String version = xwiki.getVersion(); + Integer majorVersion = null; + Integer minorVersion = null; + + if (version != null) { + if (version.indexOf('.') != -1) { + String[] components = version.split("."); + majorVersion = new Integer(components[0]); + minorVersion = new Integer(components[1]); + } + } + + ServerInfo serverInfo = + new ServerInfo(majorVersion, minorVersion, 0, version, false, xwiki.getURL("/")); + + return serverInfo.toMap(); + } + + /*********************************************************************************************** + * Spaces ************************************************************************************** + **********************************************************************************************/ + + /** + * @param token The authentication token. + * @return A list of Maps that represents SpaceSummary objects. + * @throws XWikiException + * @throws XmlRpcException An invalid token is provided. + * @category ConfluenceAPI + */ + public List getSpaces(String token) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getSpaces()", xwikiXmlRpcContext.getUser() + .getName())); + + List result = new ArrayList(); + List spaceKeys = xwiki.getSpaces(); + for (String spaceKey : spaceKeys) { + String spaceWebHome = String.format("%s.WebHome", spaceKey); + + SpaceSummary spaceSummary = null; + + if (!xwiki.exists(spaceWebHome)) { + spaceSummary = new SpaceSummary(spaceKey, spaceKey, "global", ""); + } else { + Document doc = xwiki.getDocument(spaceWebHome); + + /* If doc is null, then we don't have the rights to access the document */ + if (doc != null) { + String title = doc.getTitle(); + + if (title == null || title.equals("")) { + title = spaceKey; + } + + spaceSummary = + new SpaceSummary(spaceKey, title, "global", doc.getExternalURL("view")); + } + } + + /* Might be null if we don't have the rights to access the document */ + if (spaceSummary != null) { + result.add(spaceSummary.toMap()); + } + } + + return result; + } + + /** + * @param token The authentication token. + * @param spaceName + * @return A map representing a Space object. + * @throws XWikiException + * @throws XmlRpcException An invalid token is provided or the user doesn't have enough rights + * to access the space. + * @category ConfluenceAPI + */ + public Map getSpace(String token, String spaceName) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getSpace()", xwikiXmlRpcContext.getUser() + .getName())); + + if (!xwiki.getSpaces().contains(spaceName)) { + throw new XmlRpcException(String.format("[Space '%s' does not exist]", spaceName)); + } + + Space space = null; + String spaceWebHome = String.format("%s.WebHome", spaceName); + if (!xwiki.exists(spaceWebHome)) { + space = new Space(spaceName, "", "", "global", "", "No description available"); + } else { + Document doc = xwiki.getDocument(spaceWebHome); + + /* If doc is null, then we don't have the rights to access the document */ + if (doc != null) { + space = + new Space(spaceName, + doc.getTitle(), + "global", + doc.getExternalURL("view"), + spaceWebHome, + "No description available"); + } else { + throw new XmlRpcException(String.format("[Space '%s' cannot be accessed]", + spaceName)); + } + + } + + return space.toMap(); + } + + /** + * Add a new space. It basically creates a SpaceKey.WebHome page with no content and the space + * title as its title. + * + * @param token The authentication token. + * @param spaceMap The map representing a Space object. + * @return The newly created space as a Space object. + * @throws XWikiException + * @throws XmlRpcException Space cannot be created or it already exists and the user has not the + * rights to modify it + * @category ConfluenceAPI + */ + public Map addSpace(String token, Map spaceMap) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called addSpace()", xwikiXmlRpcContext.getUser() + .getName())); + + Space space = new Space((Map) spaceMap); + + if (xwiki.getSpaces().contains(space.getKey())) { + throw new XmlRpcException(String + .format("[Space '%s' already exists]", space.getKey())); + } + + String spaceHomePage = String.format("%s.WebHome", space.getKey()); + Document doc = xwiki.getDocument(spaceHomePage); + if (doc != null) { + doc.setContent(""); + doc.setTitle(space.getName()); + doc.save(); + + space = + new Space(space.getKey(), + space.getName(), + "global", + doc.getExternalURL(), + spaceHomePage, + space.getDescription()); + + return space.toMap(); + } else { + throw new XmlRpcException(String + .format( + "Space cannot be created or it already exists and user '%s' has not the right to modify it", + xwikiXmlRpcContext.getUser().getName())); + } + } + + /** + * Removes a space by deleting every page in it. + * + * @param token The authentication token. + * @param spaceKey + * @return True if the space has been successfully deleted. + * @throws XWikiException + * @throws XmlRpcException + * @category ConfluenceAPI + */ + public Boolean removeSpace(String token, String spaceKey) throws XWikiException, + XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called removeSpace()", xwikiXmlRpcContext.getUser() + .getName())); + + if (!xwiki.getSpaces().contains(spaceKey)) { + throw new XmlRpcException(String.format("Space '%s' does not exist.", spaceKey)); + } + + boolean spaceDeleted = true; + List pageNames = xwiki.getSpaceDocsName(spaceKey); + for (String pageName : pageNames) { + String pageFullName = String.format("%s.%s", spaceKey, pageName); + if (xwiki.exists(pageFullName)) { + Document doc = xwiki.getDocument(pageFullName); + if (doc != null) { + try { + if (!doc.getLocked()) { + doc.delete(); + } else { + /* We cannot delete a locked page, so the space is not fully deleted. */ + spaceDeleted = false; + } + } catch (XWikiException e) { + /* + * An exception here means that we haven't succeeded in deleting a page, so + * there might be some pages that still belong to the space, so the space is + * not fully deleted + */ + System.out.format("%s\n", e.getMessage()); + spaceDeleted = false; + } + } else { + spaceDeleted = false; + } + } + } + + return spaceDeleted; + } + + /*********************************************************************************************** + * Pages *************************************************************************************** + **********************************************************************************************/ + + /** + * @param token The authentication token. + * @param spaceKey + * @return A list containing PageSummary objects. + * @throws XWikiException + * @throws XmlRpcException + * @category ConfluenceAPI + */ + public List getPages(String token, String spaceKey) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getPages()", xwikiXmlRpcContext.getUser() + .getName())); + + List result = new ArrayList(); + List pageNames = xwiki.getSpaceDocsName(spaceKey); + for (String pageName : pageNames) { + String pageFullName = String.format("%s.%s", spaceKey, pageName); + + if (!xwiki.exists(pageFullName)) { + log.warn(String.format( + "Page '%s' appears to be in space '%s' but no information is available.", + pageName)); + } else { + Document doc = xwiki.getDocument(pageFullName); + + /* We only add pages we have the right to access */ + if (doc != null) { + String pageTitle = doc.getTitle(); + if (pageTitle.equals("")) { + pageTitle = pageName; + } + + PageSummary pageSummary = + new PageSummary(pageFullName, spaceKey, doc.getParent(), pageTitle, doc + .getExternalURL("view"), 0, doc.getTranslationList()); + + result.add(pageSummary.toMap()); + } + } + } + + return result; + } + + /** + * Retrieves a page. + * + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @param language The language id for the translation + * @param version The desired version. If version == 0 then the latest version is returned. + * @param minorVersion The desired minor version (ignored if version == 0). + * @return A map representing a Page object containing information about the page at version + * 'version.minorVersion' + * @throws XWikiException + * @throws XmlRpcException If the user has not the right to access the page or the page does not + * exist at version 'version.minorVersion'. + */ + public Map getPage(String token, String pageId, String language, Integer version, + Integer minorVersion) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getPage()", xwikiXmlRpcContext.getUser() + .getName())); + + if (!xwiki.exists(pageId)) { + throw new XmlRpcException(String.format("Unable to get page %s", pageId)); + } + + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + if (language.equals("") || !doc.getTranslationList().contains(language)) { + language = doc.getDefaultLanguage(); + } + + /* + * If version == 0 then don't get a specific version and keep the latest version + * returned by the previous call of getDocument(). + */ + if (version != 0) { + doc = xwiki.getDocument(doc, String.format("%d.%d", version, minorVersion)); + } + + if (doc != null) { + doc = doc.getTranslatedDocument(language); + + if (doc != null) { + String pageTitle = doc.getTitle(); + if (pageTitle.equals("")) { + pageTitle = doc.getName(); + } + + Page page = + new Page(pageId, + doc.getSpace(), + doc.getParent(), + pageTitle, + doc.getExternalURL(), + 0, + doc.getTranslationList(), + doc.getRCSVersion().at(0), + doc.getRCSVersion().at(1), + doc.getContent(), + doc.getCreationDate(), + doc.getCreator(), + doc.getContentUpdateDate(), + doc.getContentAuthor(), + doc.getName().equals("WebHome"), + "current", + true, + doc.getLanguage()); + + return page.toMap(); + } else { + throw new XmlRpcException(String.format( + "Page '%s' does not have an '%s' translation", pageId, language)); + } + } else { + throw new XmlRpcException(String.format( + "Page '%s' does not exist at version %d.%d", pageId, version, minorVersion)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } + + /** + * Utility method for getting the latest version of the page in the default language. + * + * @see XWikiXmlRpcHandler#getPage(String, String, String, Integer, Integer) + * @category ConfluenceAPI + */ + public Map getPage(String token, String pageId) throws XWikiException, XmlRpcException + { + return getPage(token, pageId, "", 0, 1); + } + + /** + * Utility method for getting the latest version of the page in a given language + * + * This method has the same signature of the Confluence API but a different semantics. While in + * Confluence the third String parameter is the page title, here it identifies the language. + * + * @see XWikiXmlRpcHandler#getPage(String, String, String, Integer, Integer) + */ + public Map getPage(String token, String pageId, String language) throws XWikiException, + XmlRpcException + { + return getPage(token, pageId, language, 0, 1); + } + + /** + * Utility method for getting a specific major version of the page in the default language + * + * @see XWikiXmlRpcHandler#getPage(String, String, String, Integer, Integer) + */ + public Map getPage(String token, String pageId, Integer version) throws XWikiException, + XmlRpcException + { + return getPage(token, pageId, "", version, 1); + } + + /** + * Utility method for getting a specific major version of the page in a given language + * + * @see XWikiXmlRpcHandler#getPage(String, String, String, Integer, Integer) + */ + public Map getPage(String token, String pageId, String language, Integer version) + throws XWikiException, XmlRpcException + { + + return getPage(token, pageId, language, version, 1); + } + + /** + * Utility method for getting a specific major.minor version of the page in the default language + * + * @see XWikiXmlRpcHandler#getPage(String, String, String, Integer, Integer) + */ + public Map getPage(String token, String pageId, Integer version, Integer minorVersion) + throws XWikiException, XmlRpcException + { + return getPage(token, pageId, "", version, minorVersion); + } + + /** + * Store a page or create it if it doesn't exist. + * + * @param token The authentication token. + * @param pageMap A map representing the Page object to be stored. + * @return A map representing a Page object with the updated information. + * @throws XWikiException + * @throws XmlRpcException + * @category ConfluenceAPI + */ + public Map storePage(String token, Map pageMap) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called storePage()", xwikiXmlRpcContext.getUser() + .getName())); + + Page page = new Page((Map) pageMap); + + Document doc = xwiki.getDocument(page.getId()); + + if (doc != null) { + if (doc.getLocked()) { + throw new XmlRpcException(String.format( + "Unable to store document. Document locked by %s", doc.getLockingUser())); + } + + if (!page.getLanguage().equals("") + && !page.getLanguage().equals(doc.getDefaultLanguage())) { + + /* Try to get the document in the translation specified in the page parameter... */ + doc = doc.getTranslatedDocument(page.getLanguage()); + + if (!doc.getLanguage().equals(page.getLanguage())) { + /* + * If we are here, then the document returned by getTranslatedDocument is the + * same of the default translation, i.e., the page in the current translation + * does not exist. So we have to create it. Here we have to use the low-level + * XWiki API because it is not possible to set the language of a Document. + */ + XWikiDocument xwikiDocument = + new XWikiDocument(page.getSpace(), page.getId()); + xwikiDocument.setLanguage(page.getLanguage()); + doc = new Document(xwikiDocument, xwikiXmlRpcContext.getXWikiContext()); + } + } + + doc.setContent(page.getContent()); + doc.setTitle(page.getTitle()); + + if (!doc.getParent().equals(page.getParentId())) { + doc.setParent(page.getParentId()); + } + + doc.save(); + + String pageTitle = doc.getTitle(); + if (pageTitle.equals("")) { + pageTitle = doc.getName(); + } + + Page newPage = + new Page(doc.getFullName(), + doc.getSpace(), + doc.getParent(), + pageTitle, + doc.getExternalURL(), + 0, + doc.getTranslationList(), + doc.getRCSVersion().at(0), + doc.getRCSVersion().at(1), + doc.getContent(), + doc.getCreationDate(), + doc.getCreator(), + doc.getContentUpdateDate(), + doc.getContentAuthor(), + doc.getName().equals("WebHome"), + "current", + true, + doc.getLanguage()); + + return newPage.toMap(); + } else { + throw new XmlRpcException(String.format("Cannot get document for page '%s'", page + .getId())); + } + } + + /** + * + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @return + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + * @category ConfluenceAPI + */ + public Boolean removePage(String token, String pageId) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called removePage()", xwikiXmlRpcContext.getUser() + .getName())); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + if (doc.getLocked()) { + throw new XmlRpcException(String.format( + "Unable to remove attachment. Document '%s' locked by '%s'", doc + .getName(), doc.getLockingUser())); + } + + doc.delete(); + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + + return true; + } + + /** + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @return A list of maps representing PageHistorySummary objects. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + * @category ConfluenceAPI + */ + public List getPageHistory(String token, String pageId) throws XWikiException, + XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called removePage()", xwikiXmlRpcContext.getUser() + .getName())); + + List result = new ArrayList(); + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + Version[] versions = doc.getRevisions(); + for (Version version : versions) { + Document docRevision = xwiki.getDocument(doc, version.toString()); + + /* + * The returned document has the right content but the wrong content update + * date, that is always equals to the current date. + */ + PageHistorySummary pageHistorySummary = + new PageHistorySummary(pageId, version.at(0), version.at(1), docRevision + .getContentAuthor(), docRevision.getContentUpdateDate()); + + result.add(pageHistorySummary.toMap()); + + } + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + + return result; + } + + /*********************************************************************************************** + * Pages (Comments) **************************************************************************** * + **********************************************************************************************/ + + /** + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @return A list of maps representing Comment objects. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + * @category ConfluenceAPI + */ + public List getComments(String token, String pageId) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getComments()", xwikiXmlRpcContext.getUser() + .getName())); + + List result = new ArrayList(); + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + Vector comments = doc.getComments(); + if (comments != null) { + for (com.xpn.xwiki.api.Object commentObject : comments) { + Property dateProperty = commentObject.getProperty("date"); + Property authorProperty = commentObject.getProperty("author"); + + if (dateProperty != null && authorProperty != null) { + Property contentProperty = commentObject.getProperty("comment"); + String content = + contentProperty != null ? (String) contentProperty.getValue() + : ""; + + Comment comment = + new Comment(String.format("%d", commentObject.getNumber()), + doc.getFullName(), + "No title", + content, + doc.getExternalURL(), + (Date) dateProperty.getValue(), + (String) authorProperty.getValue()); + + result.add(comment.toMap()); + } else { + log.warn(String.format( + "Comment %d on page %s has a null author or a null date", + commentObject.getNumber(), pageId)); + } + } + } + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + + return result; + } + + /** + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @param commentMap A map representing a Comment object. + * @return A map representing a Comment object with updated information. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + * @category ConfluenceAPI + */ + public Map addComment(String token, String pageId, Map commentMap) throws XWikiException, + XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called addComment()", xwikiXmlRpcContext.getUser() + .getName())); + + Comment comment = new Comment((Map) commentMap); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + int id = doc.createNewObject("XWiki.XWikiComments"); + com.xpn.xwiki.api.Object commentObject = doc.getObject("XWiki.XWikiComments", id); + commentObject.set("author", xwikiXmlRpcContext.getUser().getName()); + Date creationDate = new Date(); + commentObject.set("date", creationDate); + commentObject.set("comment", comment.getContent()); + + doc.save(); + + comment = + new Comment(String.format("%d", id), + pageId, + "Comment", + comment.getContent(), + doc.getExternalURL(), + creationDate, + xwikiXmlRpcContext.getUser().getName()); + + return comment.toMap(); + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + } + + /** + * + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @param commentId + * @return True if the comment has been successfully removed. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + * @category ConfluenceAPI + */ + public Boolean removeComment(String token, String pageId, String commentId) + throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called removeComment()", xwikiXmlRpcContext.getUser() + .getName())); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + if (doc.getLocked()) { + throw new XmlRpcException(String.format( + "Unable to remove attachment. Document '%s' locked by '%s'", doc + .getName(), doc.getLockingUser())); + } + + int id = Integer.parseInt(commentId); + com.xpn.xwiki.api.Object commentObject = doc.getObject("XWiki.XWikiComments", id); + doc.removeObject(commentObject); + doc.save(); + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + + return true; + } + + /*********************************************************************************************** + * Attachments ********************************************************************************* + **********************************************************************************************/ + + /** + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @return A list of maps representing Attachment objects. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + * @category ConfluenceAPI + */ + public List getAttachments(String token, String pageId) throws XWikiException, + XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getAttachments()", xwikiXmlRpcContext + .getUser().getName())); + + List result = new ArrayList(); + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + List attachments = doc.getAttachmentList(); + for (com.xpn.xwiki.api.Attachment xwikiAttachment : attachments) { + /* Due to the silly confluence API we need to convert file sizes to strings :( */ + Attachment attachment = + new Attachment(String.format("%d", xwikiAttachment.getId()), + pageId, + "No title", + xwikiAttachment.getFilename(), + String.format("%d", xwikiAttachment.getFilesize()), + xwikiAttachment.getMimeType(), + xwikiAttachment.getDate(), + xwikiAttachment.getAuthor(), + doc.getAttachmentURL(xwikiAttachment.getFilename()), + xwikiAttachment.getComment()); + + result.add(attachment.toMap()); + } + + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + + return result; + } + + /** + * + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @param fileName + * @param versionNumber (Ignored) + * @return An array of bytes with the actual attachment content. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access it + * or the attachment with the given fileName does not exist on the given page. + * @category ConfluenceAPI + */ + public byte[] getAttachmentData(String token, String pageId, String fileName, + String versionNumber) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getAttachmentData()", xwikiXmlRpcContext + .getUser().getName())); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + com.xpn.xwiki.api.Attachment xwikiAttachment = doc.getAttachment(fileName); + if (xwikiAttachment != null) { + return xwikiAttachment.getContent(); + } else { + throw new XmlRpcException(String.format( + "Attachment '%s' does not exist on page '%s'", fileName, pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + } + + /** + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @param fileName + * @return True if the attachment has been removed. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access it + * or the attachment with the given fileName does not exist on the given page. + * @category ConfluenceAPI + */ + public Boolean removeAttachment(String token, String pageId, String fileName) + throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called removeAttachment()", xwikiXmlRpcContext + .getUser().getName())); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + if (doc.getLocked()) { + throw new XmlRpcException(String.format( + "Unable to remove attachment. Document '%s' locked by '%s'", doc + .getName(), doc.getLockingUser())); + } + + com.xpn.xwiki.api.Attachment xwikiAttachment = doc.getAttachment(fileName); + if (xwikiAttachment != null) { + /* + * Here we must use low-level XWiki API because there is no way for removing an + * attachment through the XWiki User's API. + * + * Basically we use the com.xpn.xwiki.XWiki object to re-do all the steps that + * we have already done so far by using the API. It is safe because if we are + * here, we know that everything exists and we have the proper rights to do + * things. So nothing should fail. + */ + com.xpn.xwiki.XWiki baseXWiki = xwikiXmlRpcContext.getBaseXWiki(); + XWikiContext xwikiContext = xwikiXmlRpcContext.getXWikiContext(); + XWikiDocument baseXWikiDocument = baseXWiki.getDocument(pageId, xwikiContext); + XWikiAttachment baseXWikiAttachment = + baseXWikiDocument.getAttachment(fileName); + baseXWikiDocument.deleteAttachment(baseXWikiAttachment, xwikiContext); + } else { + throw new XmlRpcException(String.format( + "Attachment '%s' does not exist on page '%s'", fileName, pageId)); + } + + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + + return true; + } + + /*********************************************************************************************** + * Objects ************************************************************************************* + **********************************************************************************************/ + + /** + * @param token The authentication token. + * @return A list of maps representing XWikiClass objects + * @throws XWikiException + * @throws XmlRpcException + */ + public List getClasses(String token) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getClasses()", xwikiXmlRpcContext.getUser() + .getName())); + + List result = new ArrayList(); + + List classNames = xwiki.getClassList(); + for (String className : classNames) { + XWikiClassSummary xwikiClass = new XWikiClassSummary(className); + result.add(xwikiClass.toMap()); + } + + return result; + } + + /** + * + * @param token The authentication token. + * @param className + * @return A map representing a XWikiClass object. + * @throws XWikiException + * @throws XmlRpcException If the given class does not exist. + */ + public Map getClass(String token, String className) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getClass()", xwikiXmlRpcContext.getUser() + .getName())); + + if (!xwiki.exists(className)) { + throw new XmlRpcException(String.format("Class '%s' does not exist", className)); + } + + com.xpn.xwiki.api.Class userClass = xwiki.getClass(className); + Map> userClassPropertyToAttributesMap = + new HashMap>(); + + for (Object o : userClass.getProperties()) { + PropertyClass userClassProperty = (PropertyClass) o; + + Map attributeToValueMap = new HashMap(); + attributeToValueMap.put(XWikiClass.XWIKICLASS_ATTRIBUTE, userClassProperty + .getxWikiClass().getName()); + for (Object ucp : userClassProperty.getProperties()) { + Property property = (Property) ucp; + Object value = property.getValue(); + + if (value == null) { + attributeToValueMap.put(property.getName(), XmlRpcConstants.NULL_VALUE); + } else { + attributeToValueMap.put(property.getName(), value); + } + + } + + userClassPropertyToAttributesMap + .put(userClassProperty.getName(), attributeToValueMap); + } + + XWikiClass xwikiClass = new XWikiClass(className, userClassPropertyToAttributesMap); + + Map result = xwikiClass.toMap(); + + return result; + } + + /** + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @return A list of maps representing XWikiObject objects. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + */ + public List getObjects(String token, String pageId) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getObjects()", xwikiXmlRpcContext.getUser() + .getName())); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + + if (doc != null) { + List result = new ArrayList(); + + Map> classToObjectsMap = + doc.getxWikiObjects(); + for (String className : classToObjectsMap.keySet()) { + Vector objects = classToObjectsMap.get(className); + for (com.xpn.xwiki.api.Object object : objects) { + String prettyName = object.getPrettyName(); + if (prettyName == null || prettyName.equals("")) { + prettyName = String.format("%s[%d]", className, object.getNumber()); + } + + XWikiObjectSummary xwikiObjectSummary = + new XWikiObjectSummary(pageId, + className, + object.getNumber(), + prettyName); + + result.add(xwikiObjectSummary.toMap()); + } + } + + return result; + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Unable to get page %s", pageId)); + } + } + + /** + * The getObject function will return an XWikiObject where only non-null properties are included + * in the mapping 'field' -> 'value' + * + * In order to know all the available fields and their respective types and attributes, clients + * should refer to the object's class. + * + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @param className The class of the object. + * @param id The id (number) of the object. + * @return The XWikiObject containing the information about all the properties contained in the + * selected object. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access it + * or no object with the given id exist in the page. + */ + public Map getObject(String token, String pageId, String className, Integer id) + throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called getObject()", xwikiXmlRpcContext.getUser() + .getName())); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + + if (doc != null) { + XWikiObject xwikiObject = null; + com.xpn.xwiki.api.Object object = doc.getObject(className, id); + + if (object != null) { + Map propertyToValueMap = new HashMap(); + for (Object o : object.getProperties()) { + Property property = (Property) o; + String name = property.getName(); + + /* Send only non-null values */ + Object value = property.getValue(); + if (value != null) { + Object convertedValue = Utils.convertToXmlRpc(value); + propertyToValueMap.put(name, convertedValue); + } + } + + String prettyName = object.getPrettyName(); + if (prettyName == null || prettyName.equals("")) { + prettyName = String.format("%s[%d]", className, object.getNumber()); + } + + xwikiObject = + new XWikiObject(pageId, className, id, prettyName, propertyToValueMap); + + } else { + throw new XmlRpcException(String.format("Unable to find object id %d", id)); + } + + /* + * If we are here, xwikiObject != null, otherwise an exception would have been + * thrown. + */ + return xwikiObject.toMap(); + + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Unable to get page %s", pageId)); + } + + } + + /** + * Update the object or create a new one if it doesn't exist. + * + * @param token The authentication token. + * @param objectMap A map representing the XWikiObject to be updated/created. + * @return A map representing the XWikiObject with the updated information. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access + * it. + * + */ + public Map storeObject(String token, Map objectMap) throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called storeObject()", xwikiXmlRpcContext.getUser() + .getName())); + + XWikiObject object = new XWikiObject((Map) objectMap); + String pageId = object.getPageId(); + + if (xwiki.exists(pageId)) { + + Document doc = xwiki.getDocument(pageId); + + if (doc != null) { + if (doc.getLocked()) { + throw new XmlRpcException(String.format( + "Unable to store object. Document locked by %s", doc.getLockingUser())); + } + + com.xpn.xwiki.api.Object currentObject = + doc.getObject(object.getClassName(), object.getId()); + + /* If the object does not exist create it */ + if (currentObject == null) { + int id = doc.createNewObject(object.getClassName()); + + /* Create a copy of the passed XWikiObject with the newly created id */ + Map propertyMap = new HashMap(); + for (String property : object.getProperties()) { + propertyMap.put(property, object.get(property)); + } + object = + new XWikiObject(object.getPageId(), object.getClassName(), id, object + .getPrettyName(), propertyMap); + + /* Get the newly created object for update */ + currentObject = doc.getObject(object.getClassName(), id); + } + + /* + * We iterate on the XWikiObject-passed-as-a-parameter's properties instead of the + * one retrieved through the API because, a newly created object has no properties, + * and they should be added via set. + * + * Apparently setting properties that do not belong to the object's class is + * harmless. + */ + for (String propertyName : object.getProperties()) { + /* + * Object values are always sent as strings (or arrays/maps of strings)... let + * the actual object perform the conversion + */ + + currentObject.set(propertyName, object.get(propertyName)); + } + + doc.save(); + + return object.toMap(); + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Unable to get page %s", pageId)); + } + } + + /** + * + * @param token The authentication token. + * @param pageId The pageId in the 'Space.Page' format. + * @param className + * @param id The object's id. + * @return True if the object has been successfully deleted. + * @throws XWikiException + * @throws XmlRpcException If the page does not exist or the user has not the right to access it + * or no object with the given id exist in the page. + */ + public Boolean removeObject(String token, String pageId, String className, Integer id) + throws XWikiException, XmlRpcException + { + XWikiXmlRpcContext xwikiXmlRpcContext = + XWikiUtils.getXWikiXmlRpcContext(token, xwikiRequest, xwikiResponse, + xwikiServletContext); + XWiki xwiki = xwikiXmlRpcContext.getXWiki(); + log.info(String.format("User %s has called removeComment()", xwikiXmlRpcContext.getUser() + .getName())); + + if (xwiki.exists(pageId)) { + Document doc = xwiki.getDocument(pageId); + if (doc != null) { + if (doc.getLocked()) { + throw new XmlRpcException(String.format( + "Unable to remove attachment. Document '%s' locked by '%s'", doc + .getName(), doc.getLockingUser())); + } + + com.xpn.xwiki.api.Object commentObject = doc.getObject(className, id); + if (commentObject != null) { + doc.removeObject(commentObject); + doc.save(); + } else { + throw new XmlRpcException(String.format( + "Object %s[%d] on page '%s' does not exist", className, id, pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' cannot be accessed", pageId)); + } + } else { + throw new XmlRpcException(String.format("Page '%s' doesn't exist", pageId)); + } + + return true; + } +} Index: /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcHttpRequestConfig.java =================================================================== --- /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcHttpRequestConfig.java (revision 0) +++ /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcHttpRequestConfig.java (revision 0) @@ -0,0 +1,27 @@ +package com.xpn.xwiki.xmlrpc_new; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.xmlrpc.common.XmlRpcHttpRequestConfigImpl; + +/** + * This is an helper class for storing the current HTTP request coming from an XMLRPC client + * interacting with the XMLRPC endpoing servlet + * + * @author fmancinelli + * + */ +public class XWikiXmlRpcHttpRequestConfig extends XmlRpcHttpRequestConfigImpl +{ + private HttpServletRequest request; + + public XWikiXmlRpcHttpRequestConfig(HttpServletRequest request) + { + this.request = request; + } + + public HttpServletRequest getRequest() + { + return request; + } +} Index: /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcServlet.java =================================================================== --- /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcServlet.java (revision 0) +++ /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcServlet.java (revision 0) @@ -0,0 +1,73 @@ +package com.xpn.xwiki.xmlrpc_new; + +import java.io.IOException; +import java.net.URL; + +import javax.servlet.ServletConfig; +import javax.servlet.http.HttpServletRequest; + +import org.apache.xmlrpc.XmlRpcException; +import org.apache.xmlrpc.XmlRpcRequest; +import org.apache.xmlrpc.common.XmlRpcHttpRequestConfigImpl; +import org.apache.xmlrpc.server.PropertyHandlerMapping; +import org.apache.xmlrpc.server.RequestProcessorFactoryFactory; +import org.apache.xmlrpc.webserver.XmlRpcServlet; +import org.apache.xmlrpc.webserver.XmlRpcServletServer; + +/** + * This is the XMLRPC servlet that is used as a gateway for serving XMLRPC requests. + * + * @author fmancinelli + * + */ +public class XWikiXmlRpcServlet extends XmlRpcServlet +{ + private static final long serialVersionUID = 3745689092652029366L; + + @Override + protected PropertyHandlerMapping newPropertyHandlerMapping(URL url) throws IOException, + XmlRpcException + { + PropertyHandlerMapping mapping = new PropertyHandlerMapping(); + mapping.setTypeConverterFactory(getXmlRpcServletServer().getTypeConverterFactory()); + + RequestProcessorFactoryFactory factory = + new RequestProcessorFactoryFactory.RequestSpecificProcessorFactoryFactory() + { + protected Object getRequestProcessor(Class pClass, XmlRpcRequest pRequest) + throws XmlRpcException + { + Object proc = super.getRequestProcessor(pClass, pRequest); + + if (proc instanceof XWikiXmlRpcHandler) { + XWikiXmlRpcHandler handler = (XWikiXmlRpcHandler) proc; + HttpServletRequest request = + ((XWikiXmlRpcHttpRequestConfig) pRequest.getConfig()).getRequest(); + + handler.init(XWikiXmlRpcServlet.this, request); + } + + return proc; + } + }; + + mapping.setRequestProcessorFactoryFactory(factory); + mapping.load(Thread.currentThread().getContextClassLoader(), url); + + return mapping; + + } + + @Override + protected XmlRpcServletServer newXmlRpcServer(ServletConfig config) throws XmlRpcException + { + return new XmlRpcServletServer() + { + @Override + protected XmlRpcHttpRequestConfigImpl newConfig(HttpServletRequest request) + { + return new XWikiXmlRpcHttpRequestConfig(request); + } + }; + } +} Index: /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcUser.java =================================================================== --- /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcUser.java (revision 0) +++ /Users/fmancine/Development/Workspace.XWiki/xwiki.platform.core/src/main/java/com/xpn/xwiki/xmlrpc_new/XWikiXmlRpcUser.java (revision 0) @@ -0,0 +1,29 @@ +package com.xpn.xwiki.xmlrpc_new; + +/** + * This is an helper class for storing XMLRPC user information. + * + * @author fmancinelli + * + */ +public class XWikiXmlRpcUser +{ + private String userName; + private String remoteIp; + + public XWikiXmlRpcUser(String userName, String remoteIp) + { + this.userName = userName; + this.remoteIp = remoteIp; + } + + public String getName() + { + return userName; + } + + public String getRemoteIp() + { + return remoteIp; + } +}