package org.tizzit.plugins.server.confluence;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlrpc.XmlRpcClient;
import org.tizzit.plugins.server.confluence.data.ConfluencePage;
import org.tizzit.util.xml.SAXHelper;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import de.juwimm.cms.plugins.Constants;
import de.juwimm.cms.plugins.server.Request;
import de.juwimm.cms.plugins.server.Response;
import de.juwimm.cms.plugins.server.TizzitPlugin;
/**
* <h5>Usage / Configuration:</h5>
* <p>
* <b>tizzit-plugins.conf:</b><br/>
* <code>http://plugins.tizzit.org/ConfluenceContentPlugin=org.tizzit.plugins.server.confluence.ConfluenceContentPlugin</code>
* </p>
* <b>XML:</b>
* <pre> <getPage xmlns="http://plugins.tizzit.org/ConfluenceContentPlugin">
* <pageId dcfname="pageId" label="Page ID">557129</pageId>
* <confluenceURLs dcfname="confluenceURL" label="Confluence URLs">
* <value>http://wiki.tizzit.org</value>
* </confluenceURLs>
* <xmlRpcMethodsPrefix dcfname="xmlRpcMethodsPrefix" label="XML-RPC methods prefix">confluence1</xmlRpcMethodsPrefix>
* <useStyles dcfname="useStyles" label="Render content with styles?">
* <value>true</value>
* </useStyles>
* </getPage></pre>
*
* <h5>Element description:</h5>
* <b>mandatory:</b>
* <ul>
* <li><b>pageId</b> - The id of the Confluence page.</li>
* <li><b>confluenceURLs/value</b> - The base URL to Confluence (<code>http://<<confluence-install>></code>). This URL will be appended with {@link org.tizzit.plugins.server.confluence.DEFAULT_RPC_PATH}</li>
* </ul>
* <b>optional:</b>
* <ul>
* <li><b>xmlRpcMethodsPrefix</b> - default: <code>confluence1</code> - XML-RPC methods prefix.</li>
* <li><b>useStyles/value</b> - default: <code>false</code> - Renders the Confluence content with styles if <code>true</code>.</li>
* </ul>
*
* <h5>Output:</h5>
* <pre> <confluencePage contentStatus="current" created="1246447786000" creator="ckulawik"
* current="true" homePage="false" id="557129" modified="1255086937000"
* modifier="msimon" parentId="557083" permissions="0" space="userdoc" title="Menu bar"
* url="http://wiki.tizzit.org/display/userdoc/Menu+bar" version="12">
* <renderedContent>
* <div id="ConfluenceContent">
* <h1><a name="Menubar-MenuBar" />Menu Bar</h1>
*
* <p>The menu bar is one of the tree main functional areas in the tizzit <a href="/display/userdoc/User+Interface" title="User Interface">user interface</a>.<br /> It provides buttons/icons and drop down menus to manage your tizzit website.<br /> The buttons are grouped by their functions:</p>
* <ul>
* <li>
* <a href="#Menubar-Edit">Edit</a>
* </li>
* </ul>
* ...
* </div>
* </renderedContent>
* </confluencePage></pre>
*
* <p>
* <b>Namespace: <code>http://plugins.tizzit.org/ConfluenceContentPlugin</code></b>
* </p>
*
* @author <a href="mailto:eduard.siebert@juwimm.com">Eduard Siebert</a>
* company Juwi MacMillan Group GmbH, Walsrode, Germany
* @version $Id$
* @since tizzit-plugin-sample 15.10.2009
*/
public class ConfluenceContentPlugin implements TizzitPlugin {
private static final Log log = LogFactory.getLog(ConfluenceContentPlugin.class);
public static final String PLUGIN_NAMESPACE = Constants.PLUGIN_NAMESPACE + "ConfluenceContentPlugin";
public static final String ELEMENT_NAME_CONFLUENCE_PAGE = "confluencePage";
public static final String ELEMENT_NAME_RENDERED_CONTENT = "renderedContent";
public static final String ELEMENT_NAME_PAGE_ID = "pageId";
public static final String ELEMENT_NAME_CONFLUENCEUR_URLS = "confluenceURLs";
public static final String ELEMENT_NAME_USE_STYLES = "useStyles";
public static final String ELEMENT_NAME_XML_RPC_METHODS_PREFIX = "xmlRpcMethodsPrefix";
public static final String ELEMENT_NAME_VALUE = "value";
public static final String DEFAULT_RPC_PATH = "/rpc/xmlrpc";
public static final String DEFAULT_PLUGIN_ACCESS_KEY = "confluence1";
public static final boolean DEFAULT_USE_STYLES = false;
private ContentHandler parent;
private static final int PROCESS_NO_PROCESS = -1;
private static final int PROCESS_PAGE_ID = 10;
private static final int PROCESS_CONFLUENCE_URL = 11;
private static final int PROCESS_CONFLUENCE_URL_VALUE = 12;
private static final int PROCESS_USE_STYLES = 13;
private static final int PROCESS_USE_STYLES_VALUE = 14;
private static final int PROCESS_ACCESS_KEY = 15;
private static final int PROCESS_CONFLUENCE_PAGE = 100;
private static final int PROCESS_OTHER_NAMESPACES = 1000;
private int processing = PROCESS_NO_PROCESS;
private String pageId = null;
private String confluenceURL = null;
private boolean useStyles = false;
private String xmlRpcMethodsPrefix = "confluence1";
private XmlRpcClient rpcClient;
/* (non-Javadoc)
* @see de.juwimm.cms.plugins.server.ConquestPlugin#configurePlugin(de.juwimm.cms.plugins.server.Request, de.juwimm.cms.plugins.server.Response, org.xml.sax.ContentHandler, java.lang.Integer)
*/
public void configurePlugin(Request req, Response resp, ContentHandler ch, Integer uniquePageId) {
if (log.isDebugEnabled()) log.debug("configurePlugin() -> begin");
this.parent = ch;
if (log.isDebugEnabled()) log.debug("configurePlugin() -> end");
}
/* (non-Javadoc)
* @see de.juwimm.cms.plugins.server.ConquestPlugin#getLastModifiedDate()
*/
public Date getLastModifiedDate() {
return new Date();
}
/* (non-Javadoc)
* @see de.juwimm.cms.plugins.server.ConquestPlugin#isCacheable()
*/
public boolean isCacheable() {
return false;
}
/* (non-Javadoc)
* @see de.juwimm.cms.plugins.server.ConquestPlugin#processContent()
*/
public void processContent() {
if (log.isDebugEnabled()) log.debug("processContent() -> begin");
try {
if (StringUtils.isNotBlank(this.confluenceURL)) {
String xmlRpcUri = this.confluenceURL + DEFAULT_RPC_PATH;
if (log.isDebugEnabled()) log.debug("Creating XML-RPC-Client for URI '" + xmlRpcUri + "'.");
this.rpcClient = new XmlRpcClient(xmlRpcUri);
// TODO: provide key / value configuration and implement login
// Vector loginParams = new Vector(2);
// loginParams.add(USER_NAME);
// loginParams.add(PASSWORD);
// String loginToken = (String) rpcClient.execute("confluence1.login", loginParams);
ConfluencePage cp = this.getPage(null);
this.parent.startElement(PLUGIN_NAMESPACE, ELEMENT_NAME_CONFLUENCE_PAGE, ELEMENT_NAME_CONFLUENCE_PAGE, this.createSAXAttributes(cp));
String renderedContent = this.getRenderedContent(cp, null);
/*
* Print Confluence content into the SAX stream
*/
this.parent.startElement(PLUGIN_NAMESPACE, ELEMENT_NAME_RENDERED_CONTENT, ELEMENT_NAME_RENDERED_CONTENT, new AttributesImpl());
SAXHelper.string2sax(renderedContent, this.parent);
this.parent.endElement(PLUGIN_NAMESPACE, ELEMENT_NAME_RENDERED_CONTENT, ELEMENT_NAME_RENDERED_CONTENT);
this.parent.endElement(PLUGIN_NAMESPACE, ELEMENT_NAME_CONFLUENCE_PAGE, ELEMENT_NAME_CONFLUENCE_PAGE);
} else {
log.error("Confluence URL not found!");
}
} catch (Exception exe) {
log.error(exe.getMessage(), exe);
}
if (log.isDebugEnabled()) log.debug("processContent() -> end");
}
@SuppressWarnings("unchecked")
private ConfluencePage getPage(Vector<Object> loginToken) throws Exception {
if (log.isDebugEnabled()) log.debug("getPage() -> begin");
String method = this.getFullMethodName("getPage");
Vector<Object> pageVector = new Vector<Object>();
pageVector.add(loginToken == null ? "" : loginToken); //LOGIN
pageVector.add(this.pageId);
if (log.isDebugEnabled()) log.debug("Executing RPC method '" + method + "'.");
Hashtable<Object, Object> page = (Hashtable<Object, Object>) this.rpcClient.execute(method, pageVector);
ConfluencePage cp = new ConfluencePage();
cp.transform(page);
if (log.isDebugEnabled()) log.debug("getPage() -> end");
return cp;
}
private String getRenderedContent(ConfluencePage cp, Vector<Object> loginToken) throws Exception {
if (log.isDebugEnabled()) log.debug("getRenderedContent() -> begin");
String method = this.getFullMethodName("renderContent");
Vector<Object> renderContentVector = new Vector<Object>();
renderContentVector.add(loginToken == null ? "" : loginToken); //LOGIN
renderContentVector.add(cp.getSpace());
renderContentVector.add(cp.getId());
renderContentVector.add(cp.getContent());
if (!this.useStyles) {
Hashtable<String, String> renderPars = new Hashtable<String, String>();
renderPars.put("style", "clean");
renderContentVector.add(renderPars);
}
if (log.isDebugEnabled()) log.debug("Executing RPC method '" + method + "'.");
if (log.isDebugEnabled()) log.debug("getRenderedContent() -> end");
return (String) this.rpcClient.execute(method, renderContentVector);
}
private Attributes createSAXAttributes(ConfluencePage cp) {
AttributesImpl attribs = new AttributesImpl();
SAXHelper.setSAXAttr(attribs, "space", cp.getSpace());
SAXHelper.setSAXAttr(attribs, "url", cp.getUrl());
SAXHelper.setSAXAttr(attribs, "id", cp.getId());
SAXHelper.setSAXAttr(attribs, "homePage", Boolean.toString(cp.isHomePage()));
SAXHelper.setSAXAttr(attribs, "creator", cp.getCreator());
SAXHelper.setSAXAttr(attribs, "modifier", cp.getModifier());
SAXHelper.setSAXAttr(attribs, "contentStatus", cp.getContentStatus());
SAXHelper.setSAXAttr(attribs, "created", Long.toString(cp.getCreated().getTime()));
SAXHelper.setSAXAttr(attribs, "parentId", cp.getParentId());
SAXHelper.setSAXAttr(attribs, "current", Boolean.toString(cp.isCurrent()));
SAXHelper.setSAXAttr(attribs, "version", Integer.toString(cp.getVersion()));
SAXHelper.setSAXAttr(attribs, "permissions", Integer.toString(cp.getPermissions()));
SAXHelper.setSAXAttr(attribs, "title", cp.getTitle());
SAXHelper.setSAXAttr(attribs, "modified", Long.toString(cp.getModified().getTime()));
return attribs;
}
private String getFullMethodName(String methodName) {
return this.xmlRpcMethodsPrefix + "." + methodName;
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {
if (PLUGIN_NAMESPACE.equals(uri)) {
if (ELEMENT_NAME_PAGE_ID.equals(localName)) {
if (log.isDebugEnabled()) log.debug("Processing element '" + localName + "'.");
processing = PROCESS_PAGE_ID;
} else if (ELEMENT_NAME_CONFLUENCEUR_URLS.equals(localName)) {
if (log.isDebugEnabled()) log.debug("Processing element '" + localName + "'.");
this.processing = PROCESS_CONFLUENCE_URL_VALUE;
} else if (ELEMENT_NAME_USE_STYLES.equals(localName)) {
if (log.isDebugEnabled()) log.debug("Processing element '" + localName + "'.");
this.processing = PROCESS_USE_STYLES_VALUE;
} else if (ELEMENT_NAME_XML_RPC_METHODS_PREFIX.equals(localName)) {
if (log.isDebugEnabled()) log.debug("Processing element '" + localName + "'.");
this.processing = PROCESS_ACCESS_KEY;
} else if (ELEMENT_NAME_VALUE.equals(localName)) {
if (log.isDebugEnabled()) log.debug("Processing element '" + localName + "'.");
switch (this.processing) {
case PROCESS_USE_STYLES_VALUE:
this.processing = PROCESS_USE_STYLES;
break;
case PROCESS_CONFLUENCE_URL_VALUE:
this.processing = PROCESS_CONFLUENCE_URL;
break;
}
} else if (ELEMENT_NAME_CONFLUENCE_PAGE.equals(localName)) {
this.processing = PROCESS_CONFLUENCE_PAGE;
}
} else {
//this.parent.startElement(uri, localName, name, atts);
this.processing = PROCESS_OTHER_NAMESPACES;
}
switch (this.processing) {
case PROCESS_CONFLUENCE_PAGE:
this.parent.startElement(uri, localName, name, atts);
break;
case PROCESS_OTHER_NAMESPACES:
this.parent.startElement(uri, localName, name, atts);
break;
}
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#characters(char[], int, int)
*/
public void characters(char[] ch, int start, int length) throws SAXException {
switch (this.processing) {
case PROCESS_PAGE_ID:
this.pageId = StringUtils.trimToNull(new String(ch, start, length));
if (log.isDebugEnabled()) log.debug("Setting pageId to '" + this.pageId + "'.");
this.processing = PROCESS_NO_PROCESS;
break;
case PROCESS_CONFLUENCE_URL:
this.confluenceURL = StringUtils.trimToNull(new String(ch, start, length));
// if (this.confluenceURL != null && this.confluenceURL.endsWith("/")) {
// this.confluenceURL = this.confluenceURL.substring(0, this.confluenceURL.lastIndexOf("/"));
// }
if (log.isDebugEnabled()) log.debug("Setting confluenceURL to '" + this.confluenceURL + "'.");
this.processing = PROCESS_NO_PROCESS;
break;
case PROCESS_USE_STYLES:
this.useStyles = Boolean.parseBoolean(new String(ch, start, length).trim());
if (log.isDebugEnabled()) log.debug("Setting useStyles to '" + this.useStyles + "'.");
this.processing = PROCESS_NO_PROCESS;
break;
case PROCESS_ACCESS_KEY:
String xmlRpcMethodsPrefix = StringUtils.trimToNull(new String(ch, start, length));
if (xmlRpcMethodsPrefix != null) {
this.xmlRpcMethodsPrefix = xmlRpcMethodsPrefix;
}
if (log.isDebugEnabled()) log.debug("Setting xmlRpcMethodsPrefix to '" + this.xmlRpcMethodsPrefix + "'.");
this.processing = PROCESS_NO_PROCESS;
break;
case PROCESS_CONFLUENCE_PAGE:
this.parent.characters(ch, start, length);
break;
case PROCESS_OTHER_NAMESPACES:
this.parent.characters(ch, start, length);
break;
}
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
public void endElement(String uri, String localName, String name) throws SAXException {
switch (this.processing) {
case PROCESS_CONFLUENCE_PAGE:
this.parent.endElement(uri, localName, name);
this.processing = PROCESS_NO_PROCESS;
break;
case PROCESS_OTHER_NAMESPACES:
this.parent.endElement(uri, localName, name);
this.processing = PROCESS_NO_PROCESS;
break;
}
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endDocument()
*/
public void endDocument() throws SAXException {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
*/
public void endPrefixMapping(String prefix) throws SAXException {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
*/
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
*/
public void processingInstruction(String target, String data) throws SAXException {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
*/
public void setDocumentLocator(Locator locator) {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
*/
public void skippedEntity(String name) throws SAXException {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startDocument()
*/
public void startDocument() throws SAXException {
// do nothing
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
*/
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// do nothing
}
}