Package biz.artemis.confluence.xmlrpcwrapper

Source Code of biz.artemis.confluence.xmlrpcwrapper.RemoteWikiBroker

/**
* Created by IntelliJ IDEA.
* User: brendan
* Date: Apr 5, 2006
* Time: 4:32:57 PM
* To change this template use File | Settings | File Templates.
*/
package biz.artemis.confluence.xmlrpcwrapper;

import java.io.*;
import java.net.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.security.cert.X509Certificate;

import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcClient;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PutMethod;

//import org.apache.jackrabbit.webdav.client.methods.PutMethod;


import biz.artemis.confluence.xmlrpcwrapper.SpaceForXmlRpc.SpaceType;
import biz.artemis.util.FileUtils;

/**
* The RemoteWikiBroker will handle the the step of sending
* or receiving remote objects to and from Confluence via XMLRPC.
* <p/>
* The purpose of this class is to make it as easy as possible to interact with Confluence
* remotely with a clean, easy to use, well documented Java API. XMLRPC seems to
* be the most stable and reliable way to do this at present...though this package
* attempts to hide the details of the underlying communication layer from the public
* interface.
* <p/>
* XMLRPC is proving to be the most stable means of communicating remotely
* with Confluence at this time. 2006-04
* <p/>
* This class will also have some utility methods for managing the life cycle
* of the remote objects.
* <p/>
* <p/>
* Hashtables and possibly Vectors are used frequently in some places
* rather than more recent collection classes because of the underlying
* XML-RPC lib and what it hands back
*
* @todo extract this as an interface to allow the swapping in of alternate
* communication layers - i.e. SOAP, RMI or something else
*/
public class RemoteWikiBroker {

    // indicates the version of the API being used:
    // https://developer.atlassian.com/display/CONFDEV/Confluence+XML-RPC+and+SOAP+APIs#ConfluenceXML-RPCandSOAPAPIs-XMLRPCInformation
    public static final String CONFLUENCE_REMOTE_API_VERSION = "confluence2";
//    public static final String CONFLUENCE_REMOTE_API_VERSION = "confluence1";

    private static final String BAD_PORT = "IllegalArgumentException: port out of range";
    public static final String PERMS_FAILURE_PREFIX = "The user was authenticated on the server, but had no permissions on the space with space key: ";
    public static final String PERMS_SUCCESS_PREFIX = "The user was authenticated on the server\n and has the following permissions on the space with\n space key:";
    private static final String CONNECTION_REFUSED_ERROR = "Connection refused";
    private static final String BAD_URL_STRING = "wrong-server";
    private static final String BAD_LOGIN_ERROR = "no user could be found with this username";
    private static final String BAD_PASS_ERROR = "incorrect password";
    private static final String BAD_XMLRPC_FILE = "FileNotFoundException";
    private static final String BAD_HOST_ERROR = "UnknownHostException";
    private static final String BAD_URL_ERROR = "MalformedUrlException";
    private static final String BAD_PERMISSIONS = "You\'re not allowed to view that space, or it does not exist.";
    private static final String BAD_KEYSTOREFORMAT = "Invalid keystore format";
    private static final String ERROR_403 = "Server returned HTTP response code: 403 for URL";
    public static final String USER_ERROR_WRONG_USERNAME = "A connection to Confluence was made, but the username was not found in the system";
    public static final String USER_ERROR_WRONG_PASSWORD = "A connection to Confluence was made, the user was found, but the wrong password was used.";
    public static final String USER_ERROR_CANNOT_REACH_SERVER = "The Confluence server could not be found at this address.";
    public static final String USER_ERROR_PERMISSION_DENIED = "The user was successfully authenticated, but did not have permission to view this space.";
    public static final String USER_MESSAGE_CONNECTIVTY_SUCCESS = "Connection to server was successful.";
    public static final String USER_MESSAGE_FORBIDDEN = "The resource was forbidden (403).";
    public static final String USER_ERROR_UNKNOWN = "An unknown error occurred when trying to connect to the server. See the logs for more details.";
    public static final String BAD_TRUSTSTORE = "Location of truststore is not a valid file";
    public static final String WEBDAV_PATH_EARLY = "plugins/servlet/webdav/Global/";
    public static final String WEBDAV_PATH_LATER = "plugins/servlet/confluence/default/Global/";

    Logger log = Logger.getLogger("RemoteWikiBroker");

    /**
     * singleton stuff - generated by IDEA, keep this private
     */
    private static RemoteWikiBroker ourInstance = new RemoteWikiBroker();

    /**
     * a set of login tokens to communicate with different Confluence instances,
     * a map is used
     * to encapsulate the time the token was created as well
     */
    protected Map loginTokenMap = new HashMap();


    private Map connectionMap = new HashMap();

    /**
     * make sure new login tokens get generated next time
     */
    public void needNewLogin() {
        loginTokenMap.clear();
    }

    /**
     * singleton stuff  - generated by IDEA
     */
    public static RemoteWikiBroker getInstance() {
        return ourInstance;
    }

    /**
     * singleton stuff  - generated by IDEA
     */
    private RemoteWikiBroker() {
    }

    /**
     * Creates a local page metadata object which can then be sent
     * to Confluence with a 'store' method
     *
     * @param title
     * @param content
     * @return
     * @see PageForXmlRpc
     */
    public PageForXmlRpc createPage(String space, String title, String content) {
        PageForXmlRpc page = new PageForXmlRpc();
        page.setTitle(title);
        page.setContent(content);
        return page;
    }

    /**
     * Creates a local space metadata object which can then be sent
     * to Confluence with a 'store' method
     *
     * @param description
     * @param spaceKey
     * @param spaceName
     * @return
     * @see PageForXmlRpc
     */
    public SpaceForXmlRpc createSpace(String spaceKey, String spaceName, String description) {
        SpaceForXmlRpc space = new SpaceForXmlRpc();
        space.setSpaceKey(spaceKey);
        space.setSpaceName(spaceName);
        space.setDescription(description);
        return space;
    }

    /**
     * A convenience method to get the pageId from Confluence with only a space
     * name and a page title.
     *
     * @param space
     * @param pageTitle
     * @return page id given the page title
     * @throws IOException
     * @throws XmlRpcException
     */
    public String getPageIdFromConfluence(ConfluenceServerSettings confSettings, String space, String pageTitle) throws XmlRpcException, IOException {
        try {
            PageForXmlRpc page = populatePageXmlRpcData(confSettings, space, pageTitle);
            return page.getId();
        } catch (XmlRpcException e) {
            if (isConfluence4OrMore(confSettings)) {
                return getPageSummary(confSettings, space, pageTitle).getId();
            }
        }
        return null;
    }

    public boolean isConfluence4OrMore(ConfluenceServerSettings confSettings) throws IOException, XmlRpcException {
        Hashtable serverInfo = getServerInfo(confSettings);
        String version = (String) serverInfo.get("majorVersion");
        return Integer.parseInt(version) > 3;
    }

    /**
     * populate all the data in a PageForXmlRpc from the minimum parameters
     *
     * @param space     the space name
     * @param pageTitle the title of the page
     * @return a populated PageForXmlRpc object or an empty object if the page does not exist
     * @throws XmlRpcException
     * @throws IOException
     */
    public PageForXmlRpc populatePageXmlRpcData(ConfluenceServerSettings confSettings,
                                                String space, String pageTitle) throws XmlRpcException, IOException {
        PageForXmlRpc page = new PageForXmlRpc();
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(space);
        paramsVector.add(pageTitle);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        try {
            page.setPageParams(client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPage", paramsVector));
        } catch (XmlRpcException e) {
            // page may already exist or getPage is deprecated > 3 versions of confluence
            throw e;
        }
        return page;
    }


    /**
     * This will add a new page to the Confluence instance or if a page by this title
     * already exists it will add a new version of that page.
     * <p/>
     * If the page being added is identical to the existing page in Confluence no
     * new version is created.
     *
     * @param page
     * @return the resulting page is populated with some additional information such as pageId, etc.
     * @throws IOException
     * @throws XmlRpcException
     * @throws XmlRpcException
     */
    public PageForXmlRpc storeNewOrUpdatePage(ConfluenceServerSettings confSettings,
                                              String spaceKey,
                                              PageForXmlRpc page) throws IOException, XmlRpcException {
        // get a handle to the XMLRPC client obj, this method should be called
        // to manage the connection and make sure it's live even though there
        // is a class var.  This is actually called here for coding clarity.
        XmlRpcClient client = getXMLRPCClient(confSettings);

        // make sure loginToken is up to date
        String loginToken = getLoginToken(confSettings);

        Vector paramsVector = new Vector();
        // add the login token
        paramsVector.add(loginToken);

        // add the page  ---------------------
        page.setSpace(spaceKey);
        paramsVector.add(page.getPageParams());

        PageForXmlRpc resultPage = new PageForXmlRpc();
        // write the page  ---------------------
        try {
            resultPage.setPageParams(client.execute(CONFLUENCE_REMOTE_API_VERSION + ".storePage", paramsVector));
            return resultPage;
        } catch (XmlRpcException e) {
            // page may already exist - have to get more info on page
            log.debug("page added may already exist");
        }
        // page may already exist, get more info on page  ---------------------
        try {
            resultPage = populatePageXmlRpcData(confSettings, spaceKey, page.getTitle());
        } catch (XmlRpcException e) {
            if (isConfluence4OrMore(confSettings)) {
                resultPage = getPageSummary(confSettings, spaceKey, page.getTitle());
            }
        }
        // write the page ---------------------
        loginToken = getLoginToken(confSettings);

        paramsVector = new Vector();
        // add the login token
        paramsVector.add(loginToken);
        page.setSpace(spaceKey);
        resultPage.setContent(page.getContent());
        paramsVector.add(resultPage.getPageParams());

        // write the page
        resultPage.setPageParams(client.execute(CONFLUENCE_REMOTE_API_VERSION + ".storePage", paramsVector));

        return resultPage;

    }


    public BlogForXmlRpc storeBlog(ConfluenceServerSettings confSettings,
                                   BlogForXmlRpc blog) throws IOException, XmlRpcException {
        return storeBlog(confSettings, confSettings.spaceKey, blog);
    }

    public BlogForXmlRpc storeBlog(ConfluenceServerSettings confSettings,
                                   String spaceKey,
                                   BlogForXmlRpc blog) throws IOException, XmlRpcException {
        // get a handle to the XMLRPC client obj, this method should be called
        // to manage the connection and make sure it's live even though there
        // is a class var.  This is actually called here for coding clarity.
        XmlRpcClient client = getXMLRPCClient(confSettings);

        // make sure loginToken is up to date
        String loginToken = getLoginToken(confSettings);

        Vector paramsVector = new Vector();
        // add the login token
        paramsVector.add(loginToken);

        // add the page  ---------------------
        blog.setSpace(spaceKey);
        paramsVector.add(blog.getblogParams());

        BlogForXmlRpc resultBlog = new BlogForXmlRpc();
        // write the page  ---------------------
        try {
            resultBlog.setblogParams(client.execute(CONFLUENCE_REMOTE_API_VERSION + ".storeBlogEntry", paramsVector));
            return resultBlog;
        } catch (XmlRpcException e) {
            // blog probably already exists - have to get more info on page
//           log.debug("blog added may already exist");
        }

        //updating blog -- needs id and version

        //get the latest version of the blog
        resultBlog = getBlog(confSettings, spaceKey, blog.getTitle());

        //update the paramVector with id and version
        //(since its associated with the blogs hashtable, we can just update the blog object)
        blog.setId(resultBlog.getId());
        blog.setVersion(Integer.parseInt(resultBlog.getVersion()) + 1 + "");

        // write the page
        resultBlog.setblogParams(client.execute(CONFLUENCE_REMOTE_API_VERSION + ".storeBlogEntry", paramsVector));

        return resultBlog;

    }

    /**
     * This wrapper method was created so existing calls to this method would
     * remain unaffected, but we can catch exceptions from the core method
     * getLoginTokenThrowExceptions
     *
     * @param confSettings
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public String getLoginToken(ConfluenceServerSettings confSettings) throws IOException, XmlRpcException {
        return getLoginTokenThrowExceptions(confSettings);
    }

    /**
     * get the login token for the XmlRpc call.
     * Reuse the existing one or acquire a new one from the server if needed.
     * Confluence server login token is set as valid for 30 min. by default
     *
     * @return
     */
    public String getLoginTokenThrowExceptions(ConfluenceServerSettings confSettings)
            throws IOException, XmlRpcException {
//    public String getLoginToken(ConfluenceServerSettings confSettings) {
        boolean reloginNeeded;
        // port is part of URL
        String loginTokenKey = confSettings.url;
        String lastLoginTimeStampKey = loginTokenKey + ":timeStamp";
        String loginToken = (String) loginTokenMap.get(loginTokenKey);
        String lastLoginTimeStr = (String) loginTokenMap.get(lastLoginTimeStampKey);
        if (lastLoginTimeStr == null) lastLoginTimeStr = "0";
        long lastLoginTimeStamp = 0;
        lastLoginTimeStamp = Long.parseLong(lastLoginTimeStr);

        // check login token
        long currentTimeStamp = (new Date()).getTime();
        // if 25 minutes has not passed since login
        // check last retrieval time
        reloginNeeded = Math.abs(currentTimeStamp - lastLoginTimeStamp) > 1500000;

        // return the token if it's still valid
        if (loginToken != null && !reloginNeeded)
            return loginToken;

        Vector loginParams = new Vector(2);
        loginParams.add(confSettings.login);
        loginParams.add(confSettings.password);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        loginToken = (String) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".login", loginParams);
        loginTokenMap.put(loginTokenKey, loginToken);
        loginTokenMap.put(lastLoginTimeStampKey, String.valueOf(new Date().getTime()));
        return loginToken;
    }

    /**
     * manage and hand back the XMLRPC client connection.
     * If the url in confSettings is to an SSL protected IP, then the
     * url must indicate this by pre-pending the https:// protocol to the url.
     * Also, if the url is SSL protected, then the confSettings must include
     * the location of a valid truststore and related password.
     *
     * @param confSettings
     * @throws MalformedURLException
     * @throws {@link                IllegalArgumentException} If truststore is needed, and the
     *                               indicated location is not a valid file
     */
    protected XmlRpcClient getXMLRPCClient(ConfluenceServerSettings confSettings) throws MalformedURLException {
        XmlRpcClient clientConnection = (XmlRpcClient) connectionMap.get(confSettings.url);
        if (clientConnection != null) {
            return clientConnection;
        }
        String connectionURL = createConnectionUrl(confSettings.url);
        if (isSslUrl(connectionURL)) {
            addSSLSettings(confSettings);
        }
        clientConnection = new XmlRpcClient(connectionURL);
        connectionMap.put(confSettings.url, clientConnection);
        return clientConnection;
    }

    /**
     * creates the connection url based on the input url
     *
     * @param url Example: localhost, http://localhost:8082, https://localhost:8443
     * @return xmlrpc connection url. Example: http://localhost/rpc/xmlrpc,
     *         http://localhost:8082/rpc/xmlrpc, https://localhost:8443
     */
    protected String createConnectionUrl(String url) {
        if (!url.endsWith("/")) url += "/";
        if (!url.startsWith("http")) url = "http://" + url;

        url = url.replace("http://http://", "http://");

        return url + "rpc/xmlrpc";
    }

    /**
     * @param url
     * @return true if the given url uses https
     */
    protected boolean isSslUrl(String url) {
        return url.startsWith("https");
    }

    /**
     * sets up ssl properties and security provider,
     * given confSettings. Note: location to valid
     * certificate truststore and related password may be necessary.
     *
     * @param confSettings
     * @throws IllegalArgumentException - thrown if confSettings do
     *                                  not contain necessary security parameters. Example: location to existing
     *                                  truststore.
     */
    protected void addSSLSettings(ConfluenceServerSettings confSettings) {
        String truststore = confSettings.getTruststore();
        String trustpass = confSettings.getTrustpass();
        String trustall = confSettings.getTrustallcerts();
        if ("true".equals(trustall)) {
            addTrustAllCertsSettings();
            return;
        }
        if (truststore == null || !new File(truststore).exists()) {
            throw new IllegalArgumentException(BAD_TRUSTSTORE + ": " + truststore);
        }

        //setting the cert verification callback for ssl
        System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
        //sets the "truststore" which contains the public key of the
        //CA which signed the certificate that tomcat's using.
        //we get a (self-signed one) by exporting the keystore to a certificate and
        //then importing that cert to a truststore. See:
        //keytool -export -alias tomcat -rfc -file tomcat.crt
        //keytool -import -alias servercert -file tomcat.crt -keystore truststore
        System.setProperty("javax.net.ssl.trustStore", truststore);
        //password used when we created the truststore
        System.setProperty("javax.net.ssl.trustStorePassword", trustpass);
        //set up the security provider
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

    }

    /**
     * add security settings to trust all certificates.
     * Warning: This can expose the user to man in the middle attacks.
     * Code copied pretty much wholesale from the Apache XMLRPC library doc:
     * http://ws.apache.org/xmlrpc/ssl.html
     */
    private void addTrustAllCertsSettings() {
        //create an all trusting manager class
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        // Trust always
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        // Trust always
                    }

                    public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException {
                        // TODO Auto-generated method stub

                    }

                    public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException {
                        // TODO Auto-generated method stub

                    }
                }
        };

        // Install the all-trusting trust manager
        SSLContext sc;
        try {
            sc = SSLContext.getInstance("SSL");
            // Create empty HostnameVerifier
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            };

            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
        } catch (NoSuchAlgorithmException e) {
            log.error("Problem setting up trust manager.");
            e.printStackTrace();
        } catch (KeyManagementException e) {
            log.error("Error initializing context");
            e.printStackTrace();
        }

    }

    /**
     * @param pageId
     * @param attachment
     * @return
     * @todo -
     */
    public AttachmentForXmlRpc storeAttachment(ConfluenceServerSettings confSettings, String pageId, AttachmentForXmlRpc attachment) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pageId);
        paramsVector.add(attachment.getPageParams());

        File file = new File(attachment.getFileLocation());
        byte fileBytes[] = FileUtils.getBytesFromFile(file);
        paramsVector.add(fileBytes);

        XmlRpcClient client = getXMLRPCClient(confSettings);
        attachment.setPageParams(client.execute(CONFLUENCE_REMOTE_API_VERSION + ".addAttachment", paramsVector));
        log.info("attachment written " + attachment.getFileName());
        return attachment;
    }

    /**
     * @param confSettings
     * @param space
     * @return a map containing <pageTitle, PageForXmlRpc>. the hashtable contains all
     *         the page values which is what Confluence's XML-RPC interface returns
     * @throws XmlRpcException
     * @throws IOException
     */
    public Vector getAllServerPageSummaries(ConfluenceServerSettings confSettings, String space) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(space);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Vector pageSummaries = null;
        pageSummaries = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPages", paramsVector);
        Vector retList = null;
        if (pageSummaries != null) {
            retList = new Vector(pageSummaries.size());
            for (int i = 0; i < pageSummaries.size(); i++) {
                Hashtable pageSummHT = (Hashtable) pageSummaries.elementAt(i);
                retList.add(PageForXmlRpc.create(pageSummHT));
            }
        } else {
            retList = new Vector(0);
        }
        return retList;
    }

    /**
     * @param confSettings
     * @param space
     * @return a vector containing blog entries
     * @throws XmlRpcException
     * @throws IOException
     */
    public Vector getAllBlogEntrySummaries(ConfluenceServerSettings confSettings, String space) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(space);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Vector blogSummaries = null;
        blogSummaries = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getBlogEntries", paramsVector);
        Vector retList = null;
        if (blogSummaries != null) {
            retList = new Vector(blogSummaries.size());
            for (int i = 0; i < blogSummaries.size(); i++) {
                Hashtable pageSummHT = (Hashtable) blogSummaries.elementAt(i);
                retList.add(PageForXmlRpc.create(pageSummHT));
            }
        } else {
            retList = new Vector(0);
        }
        return retList;
    }


    /**
     * @param confSettings
     * @param pageId
     * @return
     * @throws IOException
     * @throws XmlRpcException
     */
    public List getPageHistory(ConfluenceServerSettings confSettings, String pageId) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pageId);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Vector pageHistories = null;
        pageHistories = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPageHistory", paramsVector);
        List retList = null;
        if (pageHistories != null) {
            retList = new Vector(pageHistories.size());
            for (int i = 0; i < pageHistories.size(); i++) {
                Hashtable pageHistoryHT = (Hashtable) pageHistories.elementAt(i);
                retList.add(PageHistorySummaryForXmlRpc.create(pageHistoryHT));
            }
        } else {
            retList = new ArrayList(0);
        }
        return retList;
    }


    /**
     * convenience method to get a Map of all the pages by page title
     *
     * @param confSettings
     * @param space
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public Map getAllServerPagesMapByTitle(ConfluenceServerSettings confSettings, String space) throws IOException, XmlRpcException {
        Vector pageSummaries = getAllServerPageSummaries(confSettings, space);
        List pages = convertPageSummariesToPages(confSettings, pageSummaries);
        Map pageMap = new HashMap(pages.size());
        for (int i = 0; i < pages.size(); i++) {
            PageForXmlRpc pageForXmlRpc = (PageForXmlRpc) pages.get(i);
            pageMap.put(pageForXmlRpc.getTitle(), pageForXmlRpc);
        }
        return pageMap;
    }

    /**
     * convenience method to get a Map of all the blogs by blog title
     *
     * @param confSettings
     * @param space
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public Map<String, BlogForXmlRpc> getAllServerblogsMapByTitle(ConfluenceServerSettings confSettings, String space) throws IOException, XmlRpcException {
        Vector blogSummaries = getAllBlogEntrySummaries(confSettings, space);
        List blogs = convertBlogSummariesToBlogs(confSettings, blogSummaries);
        Map blogMap = new HashMap(blogs.size());
        for (int i = 0; i < blogs.size(); i++) {
            BlogForXmlRpc blogForXmlRpc = (BlogForXmlRpc) blogs.get(i);
            blogMap.put(blogForXmlRpc.getTitle(), blogForXmlRpc);
        }
        return blogMap;
    }

    public String getSpaceHomePageId(ConfluenceServerSettings confSettings, String spaceKey) throws IOException, XmlRpcException {
        SpaceForXmlRpc space = getSpace(confSettings, spaceKey);
        if (space == null) return null;
        return space.getHomepage();
    }

    /**
     * convenience method to get a Map of all the pageSummaries by page id
     *
     * @param confSettings
     * @param space
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public Map<String, PageForXmlRpc> getAllServerPageSummariesMapById(ConfluenceServerSettings confSettings, String space) throws IOException, XmlRpcException {
        Vector pageSummaries = getAllServerPageSummaries(confSettings, space);
//        List pages = convertPageSummariesToPages(confSettings,pageSummaries);

        ArrayList pages = new ArrayList(pageSummaries);
//        for (Iterator iterator = pageSummaries.iterator(); iterator.hasNext();) {
//            PageForXmlRpc page = (PageForXmlRpc) iterator.next();
//            if (page == null) continue;
//            // now fully populate page
////            page = getPage(confSettings, page.getId());
////            if (page == null) continue;
//            pages.add(page);
//        }

        Map pageMap = new HashMap(pages.size());
        for (int i = 0; i < pages.size(); i++) {
            PageForXmlRpc pageForXmlRpc = (PageForXmlRpc) pages.get(i);
            pageMap.put(pageForXmlRpc.getId(), pageForXmlRpc);
        }
        setPagesParent(pageMap);
        return pageMap;
    }


    /**
     * convenience method to get a Map of all the pages by page id
     *
     * @param confSettings
     * @param space
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public Map getAllServerPagesMapById(ConfluenceServerSettings confSettings, String space) throws IOException, XmlRpcException {
        Vector pageSummaries = getAllServerPageSummaries(confSettings, space);
        List pages = convertPageSummariesToPages(confSettings, pageSummaries);
        Map pageMap = new HashMap(pages.size());
        for (int i = 0; i < pages.size(); i++) {
            PageForXmlRpc pageForXmlRpc = (PageForXmlRpc) pages.get(i);
            pageMap.put(pageForXmlRpc.getId(), pageForXmlRpc);
        }
        setPagesParent(pageMap);
        return pageMap;
    }

    private void setPagesParent(Map pageMapById) {
        Collection<PageForXmlRpc> pages = pageMapById.values();
        for (PageForXmlRpc page1 : pages) {
            PageForXmlRpc page = page1;
            String parentId = page.getParentId();
            if (parentId.equals("0")) {
                // should be set as space home page
                continue;
            }
            PageForXmlRpc parent = (PageForXmlRpc) pageMapById.get(parentId);
            page.setParentTitle(parent.getTitle());
        }

    }
//        // now we need the real pageSummaries....not just the page summaries that
//        // getPages returns
//        for (Iterator iterator = pageSummaries.iterator(); iterator.hasNext();) {
//            Hashtable pageSumaryHT = (Hashtable) iterator.next();
//            if (pageSumaryHT == null) continue;
//            Hashtable page = (Hashtable) getPage(confSettings, (String) pageSumaryHT.get("id"));
//            if (page == null) continue;
//            pages.put(page.get("title"), page);
//        }
//        return pages;
//    }

    /**
     * get a page
     *
     * @param confSettings
     * @param pageId
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public PageForXmlRpc getPage(ConfluenceServerSettings confSettings, String pageId) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pageId);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable page = null;
        try {
            page = (Hashtable) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPage", paramsVector);
        } catch (XmlRpcException e) {
            if (isConfluence4OrMore(confSettings)) {
                return getPageSummary(confSettings, pageId);
            }
            log.debug("Problem getting page", e);
            return null;
        }
        return PageForXmlRpc.create(page);
    }

    public PageForXmlRpc getPageSummary(ConfluenceServerSettings confSettings, String spacekey, String pagetitle) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(spacekey);
        paramsVector.add(pagetitle);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable page = null;
        page = (Hashtable) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPageSummary", paramsVector);
        return PageForXmlRpc.create(page);
    }

    public PageForXmlRpc getPageSummary(ConfluenceServerSettings confSettings, String pageid) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pageid);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable page = null;
        page = (Hashtable) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPageSummary", paramsVector);
        return PageForXmlRpc.create(page);
    }

    /**
     * get a blog
     *
     * @param confSettings
     * @param blogId
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public BlogForXmlRpc getBlog(ConfluenceServerSettings confSettings, String blogId) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(blogId);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable blog = null;
        blog = (Hashtable) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getBlog", paramsVector);
        return BlogForXmlRpc.create(blog);
    }

    /**
     * get a blog with spacekey, title, and using the current day
     *
     * @param confSettings
     * @param blogId
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public BlogForXmlRpc getBlog(ConfluenceServerSettings confSettings, String spacekey, String title) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(spacekey);
        paramsVector.add(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
        paramsVector.add(title);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable blog = null;
        blog = (Hashtable) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getBlogEntryByDayAndTitle", paramsVector);
        return BlogForXmlRpc.create(blog);
    }


    /**
     * get a page
     *
     * @param confSettings
     * @param pageId
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public List<AttachmentForXmlRpc> getAttachments(ConfluenceServerSettings confSettings, String pageId) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pageId);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable page = null;
        Vector results = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getAttachments", paramsVector);
        List<AttachmentForXmlRpc> retList = new ArrayList();
        for (Iterator iterator = results.iterator(); iterator.hasNext(); ) {
            Hashtable hashtable = (Hashtable) iterator.next();
            AttachmentForXmlRpc newAttachment = new AttachmentForXmlRpc();
            newAttachment.setPageParams(hashtable);
            retList.add(newAttachment);

        }
        return retList;
//        return PageForXmlRpc.create(page);
    }


    /**
     * get a user
     *
     * @param confSettings The server configuration
     * @param pUsername    The username of the User to retrieve
     * @return The retrieved User object
     * @throws XmlRpcException
     * @throws IOException
     */
    public UserForXmlRpc getUser(ConfluenceServerSettings confSettings, String pUsername) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUsername);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable user = null;
        user = (Hashtable) (client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getUser", paramsVector));
        return UserForXmlRpc.create(user);
    }
   
    public UserInformation getUserInformation(ConfluenceServerSettings confSettings, String pUsername) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUsername);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable info = null;
        info = (Hashtable) (client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getUserInformation", paramsVector));
        return UserInformation.create(info);
    }
   
    /**
     * @param confSettings
     * @param viewAll if true, includes deactivated users. if false, returns only active users
     * @return list of usernames
     * @throws IOException
     * @throws XmlRpcException
     */
    public List<String> getActiveUsers(ConfluenceServerSettings confSettings, boolean viewAll) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(viewAll);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Vector<String> usersList = null;
        return (Vector<String>)(client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getActiveUsers", paramsVector));
    }

    /**
     * Add a user
     *
     * @param confSettings
     * @throws XmlRpcException
     * @throws IOException
     */
    public void addUser(ConfluenceServerSettings confSettings, UserForXmlRpc pUser, String pPassword) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUser.getUserParams());
        paramsVector.add(pPassword);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        client.execute(CONFLUENCE_REMOTE_API_VERSION + ".addUser", paramsVector);
    }

    /**
     * Check if a user exists
     *
     * @return if the user exists
     * @throws XmlRpcException
     * @throws IOException
     */
    public boolean hasUser(ConfluenceServerSettings confSettings, String pUsername) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUsername);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Boolean userExists = false;
        userExists = (Boolean) (client.execute(CONFLUENCE_REMOTE_API_VERSION + ".hasUser", paramsVector));
        return userExists.booleanValue();
    }

    /**
     * get a user
     *
     * @param confSettings The server configuration
     * @param pGroupname   The username of the User to retrieve
     * @return The retrieved User object
     * @throws XmlRpcException
     * @throws IOException
     */
    public boolean hasGroup(ConfluenceServerSettings confSettings, String pGroupname) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pGroupname);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Boolean groupExists = false;
        groupExists = (Boolean) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".hasGroup", paramsVector);
        return groupExists.booleanValue();
    }

    /**
     * add a new group
     *
     * @param confSettings
     * @throws XmlRpcException
     * @throws IOException
     * @pGroupname Name of the group to create
     */
    public void addGroup(ConfluenceServerSettings confSettings, String pGroupname) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pGroupname);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        client.execute(CONFLUENCE_REMOTE_API_VERSION + ".addGroup", paramsVector);
    }

    public void addUserToGroup(ConfluenceServerSettings confSettings, String pUsername, String pGroupname) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUsername);
        paramsVector.add(pGroupname);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        client.execute(CONFLUENCE_REMOTE_API_VERSION + ".addUserToGroup", paramsVector);
    }

    public Vector getUserGroups(ConfluenceServerSettings confSettings, String pUsername) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        needNewLogin();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUsername);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Vector usergroups = null;
        usergroups = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getUserGroups", paramsVector);
        return usergroups;
    }
   
    public boolean deactivateUser(ConfluenceServerSettings confSettings, String pUsername) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUsername);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        return (Boolean) (client.execute(CONFLUENCE_REMOTE_API_VERSION + ".deactivateUser", paramsVector));
    }
    public boolean reactivateUser(ConfluenceServerSettings confSettings, String pUsername) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pUsername);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        return (Boolean) (client.execute(CONFLUENCE_REMOTE_API_VERSION + ".reactivateUser", paramsVector));
    }

    /**
     * returns a list of child page ids.
     *
     * @param confSettings
     * @param pageId
     * @return a list of child page ids
     * @throws XmlRpcException
     * @throws IOException
     */
    public List getPageChildrenIds(ConfluenceServerSettings confSettings, String pageId) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pageId);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Vector pageSummaries = null;
        pageSummaries = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getChildren", paramsVector);
        ArrayList retList = new ArrayList(pageSummaries.size());
        for (int i = 0; i < pageSummaries.size(); i++) {
            Hashtable hashtable = (Hashtable) pageSummaries.elementAt(i);
            String childPageId = PageForXmlRpc.create(hashtable).getId();
            retList.add(childPageId);
        }
        return retList;
    }

    /**
     * get a space
     *
     * @param confSettings
     * @param spaceKey
     * @return object representing the space, or null if no space exists for given spaceKey
     * @throws XmlRpcException
     * @throws IOException
     */
    public SpaceForXmlRpc getSpace(ConfluenceServerSettings confSettings, String spaceKey) throws IOException, XmlRpcException {
        SpaceForXmlRpc resultSpace = new SpaceForXmlRpc();
        Vector paramsVector = new Vector();
        needNewLogin();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(spaceKey);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable info = null;
        Hashtable<String, String> retHashtable = null;
        try {
            retHashtable = (Hashtable<String, String>) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getSpace", paramsVector);
        } catch (XmlRpcException e) {
            if (e.getMessage().contains("does not exist")) {
                log.info("space was not found");
            }
            return null;
        } catch (IOException e) {
            log.info("IO issue", e);
        } catch (Exception e) {
            if (e.getMessage().contains("does not exist")) {
                return null;
            }
        }
        if (retHashtable == null) return null;
        resultSpace.setSpaceParams(retHashtable);
        return resultSpace;
    }

    /**
     * get a space
     *
     * @param confSettings
     * @return object representing the space, or null if no space exists for given spaceKey
     * @throws XmlRpcException
     * @throws IOException
     */
    public List getSpacesSummaryList(ConfluenceServerSettings confSettings) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        needNewLogin();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable info = null;
        Vector spaceSummariesVector = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getSpaces", paramsVector);
        ArrayList retList = new ArrayList(spaceSummariesVector.size());
        for (int i = 0; i < spaceSummariesVector.size(); i++) {
            Hashtable hashtable = (Hashtable) spaceSummariesVector.elementAt(i);
            SpaceSummaryForXmlRpc spaceSummary = SpaceSummaryForXmlRpc.create(hashtable);
            retList.add(spaceSummary);
        }
        return retList;
    }


    /**
     * add a space. if the space already exists then it attempts to retrieve the
     * info on the existing space. Note: This method does not necessarily fail if the
     * space exists.
     *
     * @param confSettings
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public SpaceForXmlRpc addSpace(ConfluenceServerSettings confSettings,
                                   SpaceForXmlRpc space) throws IOException, XmlRpcException {
        // get a handle to the XMLRPC client obj, this method should be called
        // to manage the connection and make sure it's live even though there
        // is a class var.  This is actually called here for coding clarity.
        XmlRpcClient client = getXMLRPCClient(confSettings);

        // make sure loginToken is up to date
        String loginToken = getLoginToken(confSettings);

        Vector paramsVector = new Vector();
        // add the login token
        paramsVector.add(loginToken);

        // add the space  ---------------------
        paramsVector.add(space.getSpaceParams());
        //handle personal blog option
        String method = "addSpace";
        if (space.getType() == SpaceType.PERSONAL && space.getUsername() != null) {
            method = "addPersonalSpace";
            paramsVector.add(space.getUsername());
        }

        SpaceForXmlRpc resultSpace = new SpaceForXmlRpc();
        // write the space  ---------------------
        try {
            resultSpace.setSpaceParams((Hashtable<String, String>) client.execute(
                    CONFLUENCE_REMOTE_API_VERSION + "." + method, paramsVector));
            return resultSpace;
        } catch (XmlRpcException e) {
            // page may already exist
            log.info("space added may already exist");
            log.error(e.getMessage());
            e.printStackTrace();
        }
        // space may already exist, get info on existing space  ---------------------
        loginToken = getLoginToken(confSettings);
        paramsVector = new Vector();
        // add the login token
        paramsVector.add(loginToken);
        // add the space  ---------------------
        paramsVector.add(space.getSpaceKey());

        // write the page
        resultSpace.setSpaceParams((Hashtable<String, String>) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getSpace", paramsVector));
        return resultSpace;

    }

    /**
     * get a space
     *
     * @param confSettings
     * @return
     * @throws XmlRpcException
     * @throws IOException
     */
    public Hashtable getServerInfo(ConfluenceServerSettings confSettings) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        if (loginToken == null) return null;
        paramsVector.add(loginToken);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Hashtable info = null;
        return (Hashtable) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getServerInfo", paramsVector);
    }

    /**
     * converts page summaries to full blown pages
     *
     * @param confSettings
     * @param pageSummaries
     * @return PageForXmlRpc list of objects
     * @throws XmlRpcException
     * @throws IOException
     */
    public List convertPageSummariesToPages(ConfluenceServerSettings confSettings,
                                            Vector pageSummaries) throws IOException, XmlRpcException {
        ArrayList pages = new ArrayList();
        // now we need the real pageSummaries....not just the page summaries that
        // getPages returns
        for (Iterator iterator = pageSummaries.iterator(); iterator.hasNext(); ) {
            PageForXmlRpc page = (PageForXmlRpc) iterator.next();
            if (page == null) continue;
            // now fully populate page
            page = getPage(confSettings, page.getId());
            if (page == null) continue;
            pages.add(page);
        }
        return pages;
    }

    /**
     * converts blog summaries to full blown blogs
     *
     * @param confSettings
     * @param blogSummaries
     * @return BlogForXmlRpc list of objects
     * @throws XmlRpcException
     * @throws IOException
     */
    public List convertBlogSummariesToBlogs(ConfluenceServerSettings confSettings,
                                            Vector blogSummaries) throws IOException, XmlRpcException {
        ArrayList blogs = new ArrayList();
        // now we need the real blogSummaries....not just the blog summaries that
        // getBlogs returns
        for (Iterator iterator = blogSummaries.iterator(); iterator.hasNext(); ) {
            BlogForXmlRpc blog = (BlogForXmlRpc) iterator.next();
            if (blog == null) continue;
            // now fully populate blog
            blog = getBlog(confSettings, blog.getId());
            if (blog == null) continue;
            blogs.add(blog);
        }
        return blogs;
    }

    public boolean connectionActive(ConfluenceServerSettings confSettings) {
        String loginToken = null;
        try {
            loginToken = getLoginToken(confSettings);

        } catch (Throwable e) {
            log.info("connection not reachable: " + confSettings.url);
            return false;
        }
        if (loginToken == null) {
            return false;
        }
        return true;
    }

    /**
     * runs a search query against Confluence described in confSettings
     * with an empty parameters map, and a maximum number of results of 10.
     *
     * @param confSettings, connection settings
     * @param query,        search query
     * @return Vector of Hashtables, containing search results, as described:
     *         http://confluence.atlassian.com/display/DOC/Remote+API+Specification#RemoteAPISpecification-SearchResult
     * @throws XmlRpcException
     * @throws IOException
     */
    public Vector search(ConfluenceServerSettings confSettings, String query) throws IOException, XmlRpcException {
        int defaultMax = 10;
        return search(confSettings, query, null, defaultMax);
    }

    /**
     * @param confSettings, connection settings - if confSettings.login is null, the search will be
     *                      attempted anonymously
     * @param query,        search query
     * @param searchParams, Map of parameters, as described:
     *                      http://confluence.atlassian.com/display/DOC/Remote+API+Specification#RemoteAPISpecification-Search
     * @param maxResults    maximum number of results to be returned
     * @return Vector of Hashtables, containing search results, as described:
     *         http://confluence.atlassian.com/display/DOC/Remote+API+Specification#RemoteAPISpecification-SearchResult
     * @throws XmlRpcException
     * @throws IOException
     */
    public Vector search(ConfluenceServerSettings confSettings, String query, Map searchParams, int maxResults) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = (confSettings.login != null) ? getLoginToken(confSettings) : ""; //"" means anonymous user!

        //method parameters to be passed to the service
        paramsVector.add(loginToken);
        paramsVector.add(query);
        if (searchParams != null) paramsVector.add(searchParams);
        paramsVector.add(maxResults);
        XmlRpcClient client = getXMLRPCClient(confSettings);

        String method = "search";
        String api = CONFLUENCE_REMOTE_API_VERSION + "";
        String completeMethod = api + "." + method;

        Vector searchResults = (Vector) client.execute(completeMethod, paramsVector);
        return searchResults;
    }


    /**
     * check connectivity to the server and provide user readable helpful errors
     *
     * @param confSettings
     * @return user readable error message
     */
    public String checkConnectivity(ConfluenceServerSettings confSettings) {
        String token = null;
        String errorMessage = null;
        String stackTraceString = "";
        // clear the loginTokenMap so we won't get old tokens
        loginTokenMap.clear();
        try {
            token = getLoginTokenThrowExceptions(confSettings);
        } catch (Exception e) {
            stackTraceString = stackTraceToString(e);
        }
        if (token != null && (stackTraceString == null || stackTraceString.length() == 0)) {
            return USER_MESSAGE_CONNECTIVTY_SUCCESS;
        } else if (stackTraceString.contains(BAD_PASS_ERROR)) {
            return USER_ERROR_WRONG_PASSWORD;
        } else if (stackTraceString.contains(BAD_LOGIN_ERROR)) {
            return USER_ERROR_WRONG_USERNAME;
        } else if (stackTraceString.contains(BAD_URL_STRING) ||
                stackTraceString.contains(CONNECTION_REFUSED_ERROR) ||
                stackTraceString.contains(BAD_HOST_ERROR) ||
                stackTraceString.contains(BAD_XMLRPC_FILE) ||
                stackTraceString.contains(BAD_PORT) ||
                stackTraceString.contains(BAD_URL_ERROR)
                ) {
            return USER_ERROR_CANNOT_REACH_SERVER;
        } else if (stackTraceString.contains(BAD_TRUSTSTORE) ||
                stackTraceString.contains(BAD_KEYSTOREFORMAT)) {
            return BAD_TRUSTSTORE;
        } else if (stackTraceString.contains(ERROR_403)) {
            return USER_MESSAGE_FORBIDDEN;
        } else if (!"".equals(stackTraceString)) {
            log.error(stackTraceString);
            return USER_ERROR_UNKNOWN;
        }
        return USER_MESSAGE_CONNECTIVTY_SUCCESS;
    }

    /**
     * Creates and returns a {@link java.lang.String} from t�s stacktrace
     *
     * @param t Throwable whose stack trace is required
     * @return String representing the stack trace of the exception
     */
    public String stackTraceToString(Throwable t) {
        StringWriter stringWritter = new StringWriter();
        PrintWriter printWritter = new PrintWriter(stringWritter, true);
        t.printStackTrace(printWritter);
        printWritter.flush();
        stringWritter.flush();

        return stringWritter.toString();
    }


    public String getUserPermissionsForUser(ConfluenceServerSettings confSettings) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        needNewLogin();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(confSettings.spaceKey);
        XmlRpcClient client = getXMLRPCClient(confSettings);
        Vector permissions = null;
        permissions = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPermissions", paramsVector);
        StringBuilder userMessage = new StringBuilder();
        if (permissions == null) {
            userMessage.append(PERMS_FAILURE_PREFIX + "'" + confSettings.spaceKey + "'");
        } else {
            userMessage.append(PERMS_SUCCESS_PREFIX + "'" + confSettings.spaceKey + "'");
            userMessage.append(permissions);
        }
        return userMessage.toString();
    }

    /////////
    /////////
    /////////

    /**
     * retrieves a PageForXmlRpc object by the title of the page
     *
     * @param confSettings
     * @param pageName
     * @throws IOException
     */
    public PageForXmlRpc getPageByTitle(ConfluenceServerSettings confSettings, String pageName) throws IOException, XmlRpcException {


        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(confSettings.spaceKey);
        paramsVector.add(pageName.trim());

        Hashtable pageHt = null;

        XmlRpcClient client = getXMLRPCClient(confSettings);
        pageHt = (Hashtable) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getPage", paramsVector);

        PageForXmlRpc pageForXmlRpc = new PageForXmlRpc();
        pageForXmlRpc.setId((String) pageHt.get("id"));
        pageForXmlRpc.setSpace((String) pageHt.get("space"));
        pageForXmlRpc.setParentId((String) pageHt.get("parentId"));
        pageForXmlRpc.setTitle((String) pageHt.get("title"));
        pageForXmlRpc.setUrl((String) pageHt.get("url"));
        pageForXmlRpc.setVersion((String) pageHt.get("version"));
        pageForXmlRpc.setContent((String) pageHt.get("content"));
        Date createdDate = (Date) pageHt.get("created");
        pageForXmlRpc.setCreated(String.valueOf(createdDate.getTime()));
        pageForXmlRpc.setCreator((String) pageHt.get("creator"));
        Date modifiedDate = (Date) pageHt.get("modified");
        pageForXmlRpc.setModified(String.valueOf(modifiedDate.getTime()));
        pageForXmlRpc.setModifier((String) pageHt.get("modifier"));
        pageForXmlRpc.setHomePage((String) pageHt.get("homePage"));
//        pageForXmlRpc.setLocks((String) pageHt.get("locks"));

        return pageForXmlRpc;

    }


    /**
     * return a List<String> of labels for a page
     *
     * @param confSettings
     * @param pageName
     * @throws IOException
     *
     */
    public List<String> getLabelNamesByPageName(ConfluenceServerSettings confSettings, String pageName) throws IOException, XmlRpcException {
        PageForXmlRpc page = getPageByTitle(confSettings, pageName);
        String pageId = page.getId();

        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(pageId);

        Vector labelsOfPage = null;
        XmlRpcClient client = getXMLRPCClient(confSettings);
        labelsOfPage = (Vector) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".getLabelsById", paramsVector);
        List<String> retLabels = new ArrayList<String>();
        for (int i = 0; i < labelsOfPage.size(); i++) {
             Hashtable ht = (Hashtable) labelsOfPage.elementAt(i);
            String label = (Stringht.get("name");
            retLabels.add(label);

        }
        return retLabels;

    }


/////////
/////////
/////////


    /**
     * adds a lable or labels to the given pageid
     *
     * @param confSettings
     * @param pageId
     * @param labels       comma or space delimited list of labels
     * @throws IOException
     * @deprecated Use addLabels instead
     */
    public void addLabelByName(ConfluenceServerSettings confSettings, String pageId, String labels) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(labels);
        paramsVector.add(pageId);

        XmlRpcClient client = getXMLRPCClient(confSettings);
        client.execute(CONFLUENCE_REMOTE_API_VERSION + ".addLabelByName", paramsVector);
    }

    /**
     * adds labels to a Confluence ContentEntityObject
     *
     * @param confSettings connection settings - if confSettings.login is null, the search will be
     *                     attempted anonymously
     * @param labels       comma or space delimited list of spaces
     * @param pageId       id of the ContentEntityObject that will get the labels
     * @return same as the return value of the addLabelByName remote api method
     * @throws IOException
     * @throws XmlRpcException
     */
    public boolean addLabels(ConfluenceServerSettings confSettings, String labels, String pageId) throws XmlRpcException, IOException {
        Vector paramsVector = new Vector();
        String loginToken = (confSettings.login != null) ? getLoginToken(confSettings) : ""; //"" means anonymous user!

        //method parameters to be passed to the service
        paramsVector.add(loginToken);
        paramsVector.add(labels);
        paramsVector.add(pageId);
        XmlRpcClient client = getXMLRPCClient(confSettings);

        String method = "addLabelByName";
        String api = CONFLUENCE_REMOTE_API_VERSION + "";
        String completeMethod = api + "." + method;

        boolean result = (Boolean) client.execute(completeMethod, paramsVector);
        return result;
    }

    public CommentForXmlRpc addComment(ConfluenceServerSettings confSettings, CommentForXmlRpc comment) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(comment.getCommentParams());

        XmlRpcClient client = getXMLRPCClient(confSettings);

        CommentForXmlRpc retcomment = new CommentForXmlRpc();
        retcomment.setCommentParams((Hashtable<String, String>) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".addComment", paramsVector));
        log.debug("comment written " + retcomment.getTitle());
        return retcomment;
    }

    /**
     * renders page content as HTML
     *
     * @param confServer
     * @param spaceKey
     * @param pageId
     * @param content
     * @return
     * @throws IOException
     * @throws XmlRpcException
     */
    public String renderContent(ConfluenceServerSettings confServer, String spaceKey, String pageId, String content) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confServer);
        paramsVector.add(loginToken);
        paramsVector.add(spaceKey);
        paramsVector.add(pageId);
        paramsVector.add(content);
        XmlRpcClient client = getXMLRPCClient(confServer);
        Hashtable page = null;
        String renderedContent = (String) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".renderContent", paramsVector);
        return renderedContent;
    }


    // start WebDAV related methods


    /**
     * sends file to server via WebDAV. This has advantages over other methods, primarily the fact that
     * we can transfer very large files without it taxing the Confluence server and having it throw 'OutOfMemory' exceptions.
     * <p/>
     * sample usage to send a file:
     * String pageId = "3932171";
     * String fileToSendLocation = "/Users/brendan/Desktop/downloads/MyThunderbirdFeeds.opml";
     * Map pagesByIdMap = rwb.getAllServerPagesMapById(confServerSettings, spaceKey);
     * String webDAVPath = test.getWebDAVPagePath(confServerSettings.getUrl(), spaceKey, pageId, pagesByIdMap);
     * sendFileViaWebDAV(fileToSendLocation,webDAVPath, "admin", "admin");
     *
     * @param src
     * @param target   - webDAV URL such as http://localhost:8080/plugins/servlet/webdav//Global/csctest/Home/Test%20Page%20upload
     * @param username
     * @param password
     * @throws IOException
     * @throws FileNotFoundException
     */
    public void sendFileViaWebDAV(String src, String target, String username, String password) throws IOException, FileNotFoundException {

        URL baseUrl = new URL(target);

        // Source file to upload:
        File f = new File(src);
        if (!f.exists()) {
            log.error("file did not exist: " + src);
        }
        RequestEntity requestEntity = null;
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            HttpClient client = new HttpClient();
            Credentials creds = new UsernamePasswordCredentials(username, password);
            client.getState().setCredentials(AuthScope.ANY, creds);

            String webDAVPath = baseUrl.toString() + "/" + f.getName();
            try {
                webDAVPath = encodeURLForWebDAV(webDAVPath);
            } catch (URISyntaxException e) {
                e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
                log.error("file not sent to server: " + webDAVPath);
                return;
            }

            PutMethod method = new PutMethod(webDAVPath);

            fis = new FileInputStream(f);
            bis = new BufferedInputStream(fis);
            requestEntity = new InputStreamRequestEntity(bis);
            method.setRequestEntity(requestEntity);
            client.executeMethod(method);

            log.info(method.getStatusCode() + " " + method.getStatusText() + " " + src);
            if (method.getStatusCode() > 202) {
                throw new HttpException("Problem attaching file. " + method.getStatusLine());
            }
        } finally {
//            assert fis != null;
//            assert bis != null;
            if (fis != null && bis != null) {
                fis.close();
                bis.close();
            }
        }

    }

    /**
     * this generates the WebDAV path for sending an attachment to Confluence, using the earlier
     * Webdav Plugin's path (plugins/servlet/webdav/Global).
     *
     * @param server
     * @param spaceKey
     * @param pageId
     * @param pagesById
     * @return
     * @deprecated This was the original version of the method, but it assumed that the webdav path
     *             was stable. As of Webdav Plugin 2.3, the webdav path has changed. So, the recommended method is now
     *             getWebDAVPagePath(server, spacekey, pageid, pagesforxml, webdavpath) where webdavpath should probably
     *             be one of the following constants: WEBDAV_PATH_EARLY or WEBDAV_PATH_LATER.
     */
    public String getWebDAVPagePath(String server, String spaceKey, String pageId, java.util.Map<String, PageForXmlRpc> pagesById) {
        return getWebDAVPagePath(server, spaceKey, pageId, pagesById, WEBDAV_PATH_EARLY);
    }

    /**
     * this generates the WebDAV path for sending an attachment to
     * Confluence via WebDAV from the various parameter elements.
     * <p/>
     * an example of a valid WebDAV URL in this context is:
     * http://localhost:8080/plugins/servlet/webdav//Global/csctest/Home/Test%20Page%20upload
     * (spaces in names must be URL encoded to %20, more URL encoding might be needed for some chars)
     *
     * @param spaceKey
     * @param pageId
     * @param pagesById  - the method uses this to reconstruct the page hierarchy which
     *                   is necessary to hand to the WebDAV method
     * @param webdavPath the path after the url that identifies the webdav directory.
     *                   Try either: WEBDAV_PATH_EARLY (for <2.2) or WEBDAV_PATH_LATER (for 2.3+), which correspond respectively to:
     *                   plugins/servlet/webdav/Global/ and plugins/servlet/confluence/default/Global/
     * @return webdav path for the given page id
     */
    public String getWebDAVPagePath(String server, String spaceKey, String pageId, java.util.Map<String, PageForXmlRpc> pagesById, String webdavPath) {

        StringBuffer sb = new StringBuffer();
        if (!server.endsWith("/")) {
            server = server + "/";
        }
        if (!webdavPath.endsWith("/")) webdavPath += "/";
        if (!server.startsWith("http")) server = "http://" + server;
        sb.append(server + webdavPath + spaceKey + "/");

        // build the page hierarchy within
        PageForXmlRpc page = pagesById.get(pageId);
        List pageTitles = new ArrayList();
        pageTitles.add(page.getTitle());
        while (page.getParentId() != null && page.getParentId().trim().length() > 0 && !page.getParentId().equals("0")) {
            page = pagesById.get(page.getParentId());
            pageTitles.add(page.getTitle());
        }
        for (int i = pageTitles.size(); i > 0; i--) {
            sb.append(pageTitles.get(i - 1) + "/");
        }
        String pathStr = sb.toString();

        try {
            if (pathStr.endsWith("/")) {
                pathStr = pathStr.substring(0, pathStr.length() - 1);
            }
        } catch (Throwable e) {
            e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
        }
        return pathStr;
    }

    /**
     * this is a lot trickier than it should be
     *
     * @param pathStr
     * @return
     */
    public String encodeURLForWebDAV(String pathStr) throws URISyntaxException {
        // @todo - this encoding is hackey but works, should clean up, need spaces to become '%20'
        String pathStrArray[] = pathStr.split(":");
        String protocol = pathStrArray[0];
        String uriStr = pathStrArray[1];
        if (pathStrArray.length > 2) {
            uriStr = uriStr + ":" + pathStrArray[2];
        }
        URI uri = new URI(protocol, uriStr, null);
        String pathStr2 = uri.toString();
        pathStr2 = pathStr2.replace("?", "%3f"); //for some reason ? weren't getting encoded
        return pathStr2;

    }

    // end WebDAV related methods

    public enum Position {
        // See //http://jira.atlassian.com/browse/CONF-13781?focusedCommentId=136983&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_136983
        // Note: There was a topLevel option, but it caused exceptions with this method, and we didn't need it.
        /**
         * changes position of siblings: page to above target
         */
        ABOVE,
        /**
         * changes position of siblings: page to below target
         */
        BELOW,
        /**
         * makes page a child of parent
         */
        APPEND;

        public String toString() {
            switch (this) {
                case ABOVE:
                    return "above";
                case BELOW:
                    return "below";
                case APPEND:
                    return "append";
            }
            return super.toString();
        }
    }

    /**
     * moves the page represented by pageid in relation to the the page represented by
     * targetId. NOTE: Only supported with Confluence 2.9+
     *
     * @param confSettings connections settings to confluence
     * @param pageId       id for the page to be moved
     * @param targetId     id for the page that pageId will be moved in relation to
     * @param position     ABOVE, BELOW, or PAGE_APPEND.
     *                     ABOVE moves the page before the target. page and target are siblings.
     *                     BELOW moves the page after the target. page and target are siblings.
     *                     PAGE_APPEND moves the page so that target becomes the parent of page.
     * @return true (actually appears to return true always)
     * @throws XmlRpcException
     * @throws IOException
     */
    public boolean movePage(ConfluenceServerSettings confSettings, String pageId,
                            String targetId, Position position) throws XmlRpcException, IOException {
        Vector paramsVector = new Vector();
        String loginToken = (confSettings.login != null) ? getLoginToken(confSettings) : ""; //"" means anonymous user!
        String positionString = position.toString();

        //method parameters to be passed to the service
        paramsVector.add(loginToken);
        paramsVector.add(pageId);
        paramsVector.add(targetId);
        paramsVector.add(positionString);
        XmlRpcClient client = getXMLRPCClient(confSettings);

        String method = "movePage";
        String api = CONFLUENCE_REMOTE_API_VERSION + "";
        String completeMethod = api + "." + method;

        return (Boolean) client.execute(completeMethod, paramsVector);
    }


    public String convertWikiToStorageFormat(ConfluenceServerSettings confSettings, String markup) throws XmlRpcException, IOException {
      Vector paramsVector = new Vector();
      String loginToken = (confSettings.login != null) ? getLoginToken(confSettings) : ""; //"" means anonymous user!
     
      //method parameters to be passed to the service
        paramsVector.add(loginToken);
        paramsVector.add(markup);
        XmlRpcClient client = getXMLRPCClient(confSettings);

        String method = "convertWikiToStorageFormat";
        String api = CONFLUENCE_REMOTE_API_VERSION + "";
        String completeMethod = api + "." + method;

        return (String) client.execute(completeMethod, paramsVector);
    }
   
    /* UDMF methods */

    String udmfpluginkey = "com.steepdevelopment.confluence.udmf";

    public String setCreator(ConfluenceServerSettings confSettings, String username, String pageid) throws XmlRpcException, IOException {
        if (!isPluginEnabled(confSettings, udmfpluginkey)) {
            throw new IllegalStateException("UDMF plugin not installed or enabled.");
        }
        XmlRpcClient client = getXMLRPCClient(confSettings);
        String loginToken = getLoginToken(confSettings);
        Vector paramsVector = new Vector();
        paramsVector.add(loginToken);
        paramsVector.add(username);
        paramsVector.add(pageid);

        String api = "udmf";
        String method = "setCreator";
        return (String) client.execute(api + "." + method, paramsVector);
    }

    public String setLastModifier(ConfluenceServerSettings confSettings, String username, String pageid) throws XmlRpcException, IOException {
        if (!isPluginEnabled(confSettings, udmfpluginkey)) {
            throw new IllegalStateException("UDMF plugin not installed or enabled.");
        }
        XmlRpcClient client = getXMLRPCClient(confSettings);
        String loginToken = getLoginToken(confSettings);
        Vector paramsVector = new Vector();
        paramsVector.add(loginToken);
        paramsVector.add(username);
        paramsVector.add(pageid);

        String api = "udmf";
        String method = "setLastModifier";
        return (String) client.execute(api + "." + method, paramsVector);

    }

    public String setCreator(ConfluenceServerSettings confSettings, String username, String pageid, boolean usersMustExist) throws XmlRpcException, IOException {
        if (!isPluginEnabled(confSettings, udmfpluginkey)) {
            throw new IllegalStateException("UDMF plugin not installed or enabled.");
        }
        XmlRpcClient client = getXMLRPCClient(confSettings);
        String loginToken = getLoginToken(confSettings);
        Vector paramsVector = new Vector();
        paramsVector.add(loginToken);
        paramsVector.add(username);
        paramsVector.add(pageid);
        paramsVector.add((Boolean) usersMustExist);

        String api = "udmf";
        String method = "setCreator";
        return (String) client.execute(api + "." + method, paramsVector);
    }

    public String setLastModifier(ConfluenceServerSettings confSettings, String username, String pageid, boolean usersMustExist) throws XmlRpcException, IOException {
        if (!isPluginEnabled(confSettings, udmfpluginkey)) {
            throw new IllegalStateException("UDMF plugin not installed or enabled.");
        }
        XmlRpcClient client = getXMLRPCClient(confSettings);
        String loginToken = getLoginToken(confSettings);
        Vector paramsVector = new Vector();
        paramsVector.add(loginToken);
        paramsVector.add(username);
        paramsVector.add(pageid);
        paramsVector.add((Boolean) usersMustExist);

        String api = "udmf";
        String method = "setLastModifier";
        return (String) client.execute(api + "." + method, paramsVector);
    }

    public String setCreateDate(ConfluenceServerSettings confSettings, String date, String pageid) throws XmlRpcException, IOException {
        if (!isPluginEnabled(confSettings, udmfpluginkey)) {
            throw new IllegalStateException("UDMF plugin not installed or enabled.");
        }
        XmlRpcClient client = getXMLRPCClient(confSettings);
        String loginToken = getLoginToken(confSettings);
        Vector paramsVector = new Vector();
        paramsVector.add(loginToken);
        paramsVector.add(date);
        paramsVector.add(pageid);

        String api = "udmf";
        String method = "setCreateDate";
        return (String) client.execute(api + "." + method, paramsVector);
    }

    public String setLastModifiedDate(ConfluenceServerSettings confSettings, String date, String pageid) throws XmlRpcException, IOException {
        if (!isPluginEnabled(confSettings, udmfpluginkey)) {
            throw new IllegalStateException("UDMF plugin not installed or enabled.");
        }
        XmlRpcClient client = getXMLRPCClient(confSettings);
        String loginToken = getLoginToken(confSettings);
        Vector paramsVector = new Vector();
        paramsVector.add(loginToken);
        paramsVector.add(date);
        paramsVector.add(pageid);

        String api = "udmf";
        String method = "setLastModifiedDate";
        return (String) client.execute(api + "." + method, paramsVector);
    }

    public boolean isPluginEnabled(ConfluenceServerSettings confSettings, String pluginkey) throws XmlRpcException, IOException {
        XmlRpcClient client = getXMLRPCClient(confSettings);
        String loginToken = getLoginToken(confSettings);
        Vector paramsVector = new Vector();
        paramsVector.add(loginToken);
        paramsVector.add(pluginkey);

        String api = CONFLUENCE_REMOTE_API_VERSION + "";
        String method = "isPluginEnabled";
        return (Boolean) client.execute(api + "." + method, paramsVector);
    }
   
   
    public boolean addPermissionsToSpace(ConfluenceServerSettings confSettings, Vector<String> permissions, String userOrGroup) throws IOException, XmlRpcException {
        Vector paramsVector = new Vector();
        String loginToken = getLoginToken(confSettings);
        paramsVector.add(loginToken);
        paramsVector.add(permissions);
        paramsVector.add(userOrGroup);
        paramsVector.add(confSettings.getSpaceKey());

        XmlRpcClient client = getXMLRPCClient(confSettings);

        Boolean ret = (Boolean) client.execute(CONFLUENCE_REMOTE_API_VERSION + ".addPermissionsToSpace", paramsVector);
        log.debug("assigned permissions to space '" + confSettings.getSpaceKey() + "' for '" + userOrGroup + "'");
        return ret;
    }
}
TOP

Related Classes of biz.artemis.confluence.xmlrpcwrapper.RemoteWikiBroker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.