/**
* 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 = (String) ht.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;
}
}