package org.bsc.maven.confluence.plugin; import java.io.File; import java.util.Collections; import org.apache.maven.project.MavenProject; import biz.source_code.miniTemplator.MiniTemplator; import biz.source_code.miniTemplator.MiniTemplator.VariableNotDefinedException; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.util.List; import java.util.Map; import org.apache.maven.plugins.annotations.Parameter; import org.bsc.confluence.ConfluenceService; import org.bsc.confluence.ConfluenceService.Model; import org.bsc.confluence.ConfluenceService.Storage; import org.bsc.confluence.ConfluenceService.Storage.Representation; import org.bsc.confluence.model.ProcessUriException; import org.bsc.confluence.model.Site; import rx.functions.Func2; import static java.lang.String.format; /** * * @author bsorrentino */ public abstract class AbstractConfluenceMojo extends AbstractBaseConfluenceMojo { /** * Maven Project */ @Parameter(property = "project", readonly = true, required = true) protected MavenProject project; /** * Home page template source. Template name will be used also as template source for children */ @Parameter(defaultValue = "${basedir}/src/site/confluence/template.wiki") protected java.io.File templateWiki; /** * attachment folder */ @Parameter(defaultValue = "${basedir}/src/site/confluence/attachments") private java.io.File attachmentFolder; /** * children folder */ @Parameter(defaultValue = "${basedir}/src/site/confluence/children") private java.io.File childrenFolder; /** * During publish of documentation related to a new release, if it's true, the pages related to SNAPSHOT will be removed */ @Parameter(property = "confluence.removeSnapshots", required = false, defaultValue = "false") protected boolean removeSnapshots = false; /** * prefix child page with the title of the parent * * @since 4.9 */ @Parameter(property = "confluence.childrenTitlesPrefixed", required = false, defaultValue = "true") protected boolean childrenTitlesPrefixed = true; /** * Labels to add */ @Parameter() java.util.List<String> labels; /** * Confluence Page Title * @since 3.1.3 */ @Parameter(alias="title", property = "project.build.finalName", required = false) private String title; /** * Children files extension * @since 3.2.1 */ @Parameter(property = "wikiFilesExt", required = false, defaultValue=".wiki") private String wikiFilesExt; /** * The file encoding of the source files. * */ @Parameter( property="encoding", defaultValue="${project.build.sourceEncoding}" ) private String encoding; /** * */ public AbstractConfluenceMojo() { } protected File getChildrenFolder() { return childrenFolder; } protected File getAttachmentFolder() { return attachmentFolder; } /** * * @return */ public String getEncoding() { return encoding; } /** * * @param encoding */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * * @return */ protected final Charset getCharset() { if( encoding == null ) { getLog().warn("encoding is null! default charset will be used"); return Charset.defaultCharset(); } try { Charset result = Charset.forName(encoding); return result; } catch (UnsupportedCharsetException e) { getLog().warn( String.format("encoding [%s] is not valid! default charset will be used", encoding)); return Charset.defaultCharset(); } } /** * * @return */ protected final String getTitle() { return title; } /** * * @param title */ public void setTitle(String title) { this.title = title; } /** * * @return */ public String getFileExt() { return (wikiFilesExt.charAt(0)=='.' ) ? wikiFilesExt : ".".concat(wikiFilesExt); } public MavenProject getProject() { return project; } public boolean isRemoveSnapshots() { return removeSnapshots; } public boolean isSnapshot() { final String version = project.getVersion(); return (version != null && version.endsWith("-SNAPSHOT")); } public boolean isChildrenTitlesPrefixed() { return childrenTitlesPrefixed; } public List<String> getLabels() { if( labels==null ) { return Collections.emptyList(); } return labels; } /** * initialize properties shared with template */ protected void initTemplateProperties() { processProperties(); getProperties().put("pageTitle", getTitle()); getProperties().put("artifactId", project.getArtifactId()); getProperties().put("version", project.getVersion()); getProperties().put("groupId", project.getGroupId()); getProperties().put("name", project.getName()); getProperties().put("description", project.getDescription()); final java.util.Properties projectProps = project.getProperties(); if( projectProps!=null ) { for(Map.Entry<Object,Object> e : projectProps.entrySet()){ getProperties().put( String.valueOf(e.getKey()), String.valueOf(e.getValue()) ); } } } public void addStdProperties(MiniTemplator t) { java.util.Map<String, String> props = getProperties(); if (props == null || props.isEmpty()) { getLog().info("no properties set!"); } else { for (java.util.Map.Entry<String, String> e : props.entrySet()) { try { t.setVariable(e.getKey(), e.getValue(), true /* isOptional */); } catch (VariableNotDefinedException e1) { getLog().debug(String.format("variable %s not defined in template", e.getKey())); } } } } protected <T extends Site.Page> Model.Page generateChild(final ConfluenceService confluence, final T child, String spaceKey, String parentPageTitle, String titlePrefix) { java.net.URI source = child.getUri(getFileExt()); getLog().info( String.format("generateChild spacekey=[%s] parentPageTtile=[%s]\n%s", spaceKey, parentPageTitle, child.toString())); try { if (!isSnapshot() && isRemoveSnapshots()) { final String snapshot = titlePrefix.concat("-SNAPSHOT"); final Model.Page page = confluence.getPage(spaceKey, parentPageTitle); boolean deleted = confluence.removePage(page, snapshot); if (deleted) { getLog().info(String.format("Page [%s] has been removed!", snapshot)); } } final String pageName = !isChildrenTitlesPrefixed() ? child.getName() : String.format("%s - %s", titlePrefix, child.getName()); Model.Page result = confluence.getOrCreatePage(spaceKey, parentPageTitle, pageName); if ( source != null ) { final Model.Page pageToUpdate = result; result = Site.processUri(source, this.getTitle(), new Func2<InputStream,Storage.Representation,Model.Page>() { @Override public Model.Page call(InputStream is, Representation r) { try { final MiniTemplator t = new MiniTemplator.Builder() .setSkipUndefinedVars(true) .build( is, getCharset() ); if( !child.isIgnoreVariables() ) { addStdProperties(t); t.setVariableOpt("childTitle", pageName); } return confluence.storePage(pageToUpdate, new Storage(t.generateOutput(), r) ); } catch (Exception ex) { final String msg = format("error storing page [%s]", pageToUpdate.getTitle()); throw new RuntimeException(msg, ex); } } }) ; } else { result = confluence.storePage(result); } for( String label : child.getComputedLabels() ) { confluence.addLabelByName(label, Long.parseLong(result.getId()) ); } child.setName( pageName ); return result; } catch (RuntimeException re ){ throw re; } catch (Exception e) { final String msg = "error loading template"; //getLog().error(msg, e); throw new RuntimeException(msg, e); } } /** * Issue 46 * **/ private void processProperties() { for( Map.Entry<String,String> e : this.getProperties().entrySet() ) { try { String v = e.getValue(); if( v == null ) { getLog().warn( String.format("property [%s] has null value!", e.getKey())); continue; } final java.net.URI uri = new java.net.URI( v ); if( uri.getScheme() == null ) { continue; } getProperties().put( e.getKey(), processUri( uri, getCharset() )); } catch (ProcessUriException ex) { getLog().warn( String.format("error processing value of property [%s]\n%s", e.getKey(), ex.getMessage())); if( ex.getCause() != null ) getLog().debug( ex.getCause() ); } catch (URISyntaxException ex) { // DO Nothing getLog().debug( String.format("property [%s] is not a valid uri", e.getKey())); } } } /** * * @param uri * @return * @throws org.bsc.maven.reporting.AbstractConfluenceMojo.ProcessUriException */ private String processUri( java.net.URI uri, final Charset charset ) throws ProcessUriException { try { return Site.processUri(uri, this.getTitle(), new Func2<InputStream, Representation, String>() { @Override public String call(InputStream is, Representation r) { try { return AbstractConfluenceMojo.this.toString( is, charset ); } catch (IOException ex) { throw new RuntimeException(ex); } } }) ; } catch (Exception ex) { throw new ProcessUriException("error reading content!", ex); } } /** * * @param reader * @return * @throws IOException */ private String toString(java.io.InputStream stream, Charset charset) throws IOException { if (stream == null) { throw new IllegalArgumentException("stream"); } try( final java.io.Reader r = new java.io.InputStreamReader(stream, charset) ) { final StringBuilder contents = new StringBuilder(4096); int c; while ((c = r.read()) != -1) { contents.append((char) c); } return contents.toString(); } } }