Skip to content

Commit

Permalink
Get closer to supporting Confluence 4.0, partially fixes JENKINS-11276
Browse files Browse the repository at this point in the history
The Confluence 4.0 update includes a new SOAP endpoint (v2), and the
v1 endpoint's getPage() method now results in a remote error --
suggesting instead to use getPageSummary().  The file attachment
functionality did not rely on the wiki content being returned in
getPage(), so we now use getPageSummary() for doing file attachments.

Confluence 4.0 also introduces a new page content storage format,
which means wiki markup is no longer supported.  That means the page
editing feature of the plugin will need to be updated to work with the
v2 API's XHTML storage format.  For now, we're just fixing the file
attachment bug, and gracefully degrading on page content editing.
  • Loading branch information
Joe Hansche committed Oct 16, 2011
1 parent ef76f26 commit fda581a
Show file tree
Hide file tree
Showing 10 changed files with 17,378 additions and 66 deletions.
3 changes: 2 additions & 1 deletion pom.xml
Expand Up @@ -75,9 +75,10 @@
<artifactId>axistools-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<packageSpace>hudson.plugins.confluence.soap</packageSpace>
<sourceDirectory>src/main/wsdl/</sourceDirectory>
<outputDirectory>target/generated-sources/localizer</outputDirectory>
<packageSpace>jenkins.plugins.confluence.soap</packageSpace>
<subPackageByFileName>true</subPackageByFileName>
</configuration>
<executions>
<execution>
Expand Down
@@ -1,6 +1,9 @@

package com.myyearbook.hudson.plugins.confluence;

import com.myyearbook.hudson.plugins.confluence.wiki.editors.MarkupEditor;
import com.myyearbook.hudson.plugins.confluence.wiki.editors.MarkupEditor.TokenNotFoundException;

import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
Expand All @@ -10,28 +13,21 @@
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.plugins.confluence.soap.RemoteAttachment;
import hudson.plugins.confluence.soap.RemotePage;
import hudson.plugins.confluence.soap.RemotePageUpdateOptions;
import hudson.plugins.confluence.soap.RemoteSpace;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import hudson.util.DescribableList;
import hudson.util.FormValidation;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.export.Exported;

import net.sf.json.JSONObject;

import com.myyearbook.hudson.plugins.confluence.wiki.editors.MarkupEditor;
import com.myyearbook.hudson.plugins.confluence.wiki.editors.MarkupEditor.TokenNotFoundException;

import java.io.File;
import java.io.IOException;
import java.net.URLConnection;
Expand All @@ -40,6 +36,12 @@
import java.util.List;
import java.util.logging.Logger;

import jenkins.plugins.confluence.soap.v1.RemoteAttachment;
import jenkins.plugins.confluence.soap.v1.RemotePage;
import jenkins.plugins.confluence.soap.v1.RemotePageSummary;
import jenkins.plugins.confluence.soap.v1.RemotePageUpdateOptions;
import jenkins.plugins.confluence.soap.v1.RemoteSpace;

public class ConfluencePublisher extends Notifier implements Saveable {
private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";

Expand All @@ -50,8 +52,8 @@ public class ConfluencePublisher extends Notifier implements Saveable {
private final String spaceName;
private final String pageName;

private DescribableList<MarkupEditor, Descriptor<MarkupEditor>> editors =
new DescribableList<MarkupEditor, Descriptor<MarkupEditor>>(this);
private DescribableList<MarkupEditor, Descriptor<MarkupEditor>> editors = new DescribableList<MarkupEditor, Descriptor<MarkupEditor>>(
this);

@DataBoundConstructor
public ConfluencePublisher(String siteName, final String spaceName, final String pageName,
Expand Down Expand Up @@ -142,10 +144,10 @@ public String getSpaceName() {
}

protected boolean performAttachments(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener, ConfluenceSession confluence, RemotePage pageData)
BuildListener listener, ConfluenceSession confluence, final RemotePageSummary pageData)
throws IOException, InterruptedException {
final long pageId = pageData.getId();

final long pageId = pageData.getId();
FilePath ws = build.getWorkspace();

if (ws == null) {
Expand Down Expand Up @@ -251,7 +253,7 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
return true;
}

final RemotePage pageData = confluence.getPage(spaceName, pageName);
final RemotePageSummary pageData = confluence.getPageSummary(spaceName, pageName);

// Perform attachment uploads
try {
Expand All @@ -262,13 +264,20 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
e.printStackTrace(listener.getLogger());
}

// Perform wiki replacements
try {
result &= this.performWikiReplacements(build, launcher, listener, confluence, pageData);
} catch (IOException e) {
e.printStackTrace(listener.getLogger());
} catch (InterruptedException e) {
e.printStackTrace(listener.getLogger());
// Wiki editing is only supported in versions prior to 4.0
if (!confluence.isVersion4() && pageData instanceof RemotePage) {
// Perform wiki replacements
try {
result &= this.performWikiReplacements(build, launcher, listener, confluence,
(RemotePage) pageData);
} catch (IOException e) {
e.printStackTrace(listener.getLogger());
} catch (InterruptedException e) {
e.printStackTrace(listener.getLogger());
}
} else if (!editors.isEmpty()) {
log(listener, "Confluence version 4.0 has moved to a new page storage format.");
log(listener, "Not performing page edits!");
}

// Not returning `result`, because this publisher should not
Expand Down Expand Up @@ -316,7 +325,7 @@ protected boolean performWikiReplacements(AbstractBuild<?, ?> build, Launcher la

/**
* Recursively scan a directory, returning all files encountered
*
*
* @param artifactsDir
* @return
*/
Expand All @@ -334,7 +343,7 @@ private List<FilePath> findArtifacts(File artifactsDir) {

/**
* Log helper
*
*
* @param listener
* @param message
*/
Expand Down Expand Up @@ -395,10 +404,12 @@ public FormValidation doPageNameCheck(@QueryParameter final String siteName,

try {
ConfluenceSession confluence = site.createSession();
RemotePage page = confluence.getPage(spaceName, pageName);
RemotePageSummary page = confluence.getPageSummary(spaceName, pageName);

if (page != null) {
return FormValidation.ok("OK: " + page.getTitle());
}

return FormValidation.error("Page not found");
} catch (RemoteException re) {
return FormValidation.error(re, re.getMessage());
Expand All @@ -420,9 +431,11 @@ public FormValidation doSpaceNameCheck(@QueryParameter final String siteName,
try {
ConfluenceSession confluence = site.createSession();
RemoteSpace space = confluence.getSpace(spaceName);

if (space != null) {
return FormValidation.ok("OK: " + space.getName());
}

return FormValidation.error("Space not found");
} catch (RemoteException re) {
return FormValidation.error(re, re.getMessage());
Expand All @@ -448,8 +461,7 @@ public List<ConfluenceSite> getSites() {
}

@Override
public boolean isApplicable(
@SuppressWarnings("rawtypes") Class<? extends AbstractProject> p) {
public boolean isApplicable(@SuppressWarnings("rawtypes") Class<? extends AbstractProject> p) {
return sites != null && sites.size() > 0;
}

Expand Down
Expand Up @@ -2,12 +2,6 @@
package com.myyearbook.hudson.plugins.confluence;

import hudson.FilePath;
import hudson.plugins.confluence.soap.ConfluenceSoapService;
import hudson.plugins.confluence.soap.RemoteAttachment;
import hudson.plugins.confluence.soap.RemotePage;
import hudson.plugins.confluence.soap.RemotePageUpdateOptions;
import hudson.plugins.confluence.soap.RemoteServerInfo;
import hudson.plugins.confluence.soap.RemoteSpace;

import java.io.ByteArrayOutputStream;
import java.io.File;
Expand All @@ -19,9 +13,17 @@
import java.nio.channels.WritableByteChannel;
import java.rmi.RemoteException;

import jenkins.plugins.confluence.soap.v1.ConfluenceSoapService;
import jenkins.plugins.confluence.soap.v1.RemoteAttachment;
import jenkins.plugins.confluence.soap.v1.RemotePage;
import jenkins.plugins.confluence.soap.v1.RemotePageSummary;
import jenkins.plugins.confluence.soap.v1.RemotePageUpdateOptions;
import jenkins.plugins.confluence.soap.v1.RemoteServerInfo;
import jenkins.plugins.confluence.soap.v1.RemoteSpace;

/**
* Connection to Confluence
*
*
* @author Joe Hansche <jhansche@myyearbook.com>
*/
public class ConfluenceSession {
Expand All @@ -36,30 +38,34 @@ public class ConfluenceSession {
*/
private final String token;

private final RemoteServerInfo serverInfo;

/**
* Constructor
*
*
* @param service
* @param token
*/
/* package */ConfluenceSession(final ConfluenceSoapService service, final String token) {
/* package */ConfluenceSession(final ConfluenceSoapService service, final String token,
final RemoteServerInfo info) {
this.service = service;
this.token = token;
this.serverInfo = info;
}

/**
* Get server info
*
*
* @return {@link RemoteServerInfo} instance
* @throws RemoteException
*/
public RemoteServerInfo getServerInfo() throws RemoteException {
return this.service.getServerInfo(this.token);
public RemoteServerInfo getServerInfo() {
return this.serverInfo;
}

/**
* Get a Space by key name
*
*
* @param spaceKey
* @return {@link RemoteSpace} instance
* @throws RemoteException
Expand All @@ -70,16 +76,49 @@ public RemoteSpace getSpace(String spaceKey) throws RemoteException {

/**
* Get a Page by Space and Page key names
*
*
* @param spaceKey
* @param pageKey
* @return {@link RemotePage} instance
* @throws RemoteException
* @throws UnsupportedOperationException if attempting to call this method
* against a 4.0 or newer server
* @deprecated Calling this method on a Confluence 4.0+ server will result
* in a RemoteException
*/
@Deprecated
public RemotePage getPage(String spaceKey, String pageKey) throws RemoteException {
if (isVersion4()) {
// This v1 API is broken in Confluence 4.0 and newer.
throw new UnsupportedOperationException(
"This API is not supported on Confluence version 4.0 and newer. Use getPageSummary()");
}

return this.service.getPage(this.token, spaceKey, pageKey);
}

/**
* This method is an attempt to bridge the gap between the deprecated v1
* APIs and the as-yet unimplemented v2 APIs. The v1 getPage() API no longer
* works on version 4.0+ servers, but the v2 getPage() does. The v1
* getPageSummary() is the same functionality as getPage(), minus the
* existing page content.
*
* @param spaceKey
* @param pageKey
* @return
* @throws RemoteException
*/
public RemotePageSummary getPageSummary(final String spaceKey, final String pageKey)
throws RemoteException {
if (!isVersion4()) {
// This method did not exist in the pre-4.0 v1 SOAP API
return this.getPage(spaceKey, pageKey);
}

return this.service.getPageSummary(this.token, spaceKey, pageKey);
}

public RemotePage storePage(final RemotePage page) throws RemoteException {
return this.service.storePage(this.token, page);
}
Expand All @@ -91,7 +130,7 @@ public RemotePage updatePage(final RemotePage page, final RemotePageUpdateOption

/**
* Get all attachments for a page
*
*
* @param pageId
* @return Array of {@link RemoteAttachment}s
* @throws RemoteException
Expand All @@ -102,7 +141,7 @@ public RemoteAttachment[] getAttachments(long pageId) throws RemoteException {

/**
* Attach the file
*
*
* @param pageId
* @param fileName
* @param contentType
Expand All @@ -112,8 +151,7 @@ public RemoteAttachment[] getAttachments(long pageId) throws RemoteException {
* @throws RemoteException
*/
public RemoteAttachment addAttachment(long pageId, String fileName, String contentType,
String comment, byte[] bytes)
throws RemoteException {
String comment, byte[] bytes) throws RemoteException {
RemoteAttachment attachment = new RemoteAttachment();
attachment.setPageId(pageId);
attachment.setFileName(sanitizeFileName(fileName));
Expand All @@ -125,7 +163,7 @@ public RemoteAttachment addAttachment(long pageId, String fileName, String conte

/**
* Attach the file
*
*
* @param pageId
* @param file
* @param contentType
Expand All @@ -135,8 +173,7 @@ public RemoteAttachment addAttachment(long pageId, String fileName, String conte
* @throws InterruptedException
*/
public RemoteAttachment addAttachment(long pageId, FilePath file, String contentType,
String comment)
throws IOException, InterruptedException {
String comment) throws IOException, InterruptedException {
ByteArrayOutputStream baos;
baos = new ByteArrayOutputStream((int) file.length());
file.copyTo(baos);
Expand All @@ -146,7 +183,7 @@ public RemoteAttachment addAttachment(long pageId, FilePath file, String content

/**
* Attach the file
*
*
* @param pageId
* @param file
* @param contentType
Expand Down Expand Up @@ -180,7 +217,7 @@ public RemoteAttachment addAttachment(long pageId, File file, String contentType

/**
* Sanitize the attached filename, per Confluence restrictions
*
*
* @param fileName
* @return
*/
Expand All @@ -190,4 +227,13 @@ public static String sanitizeFileName(String fileName) {
}
return hudson.Util.fixEmptyAndTrim(fileName.replace('+', '_').replace('&', '_'));
}

/**
* Returns true if this server is version 4.0 or newer.
*
* @return
*/
public boolean isVersion4() {
return this.serverInfo.getMajorVersion() >= 4;
}
}

0 comments on commit fda581a

Please sign in to comment.