001package org.nasdanika.html.model.app.gen.maven; 002 003import java.io.File; 004import java.io.FileNotFoundException; 005import java.io.IOException; 006import java.io.PrintStream; 007import java.util.Arrays; 008import java.util.Collection; 009import java.util.List; 010import java.util.Map; 011import java.util.Map.Entry; 012import java.util.concurrent.CancellationException; 013 014import org.apache.maven.plugin.AbstractMojo; 015import org.apache.maven.plugin.MojoExecutionException; 016import org.apache.maven.plugins.annotations.LifecyclePhase; 017import org.apache.maven.plugins.annotations.Mojo; 018import org.apache.maven.plugins.annotations.Parameter; 019import org.apache.maven.project.MavenProject; 020import org.eclipse.emf.common.util.DiagnosticException; 021import org.eclipse.emf.common.util.URI; 022import org.nasdanika.common.Context; 023import org.nasdanika.common.DiagramGenerator; 024import org.nasdanika.common.DiagramGeneratorImpl; 025import org.nasdanika.common.NasdanikaException; 026import org.nasdanika.common.ProgressMonitor; 027import org.nasdanika.common.Status; 028import org.nasdanika.common.Util; 029import org.nasdanika.html.model.app.gen.ActionSiteGenerator; 030 031/** 032 * Generates action site. 033 */ 034@Mojo(name = "generate-action-site", defaultPhase = LifecyclePhase.SITE) 035public class ActionSiteGeneratorMojo extends AbstractMojo { 036 037 @Parameter(defaultValue = "target/action-site") 038 private File outputDirectory; 039 040 @Parameter(defaultValue = "target/action-site-work-dir") 041 private File workDirectory; 042 043 @Parameter() 044 private boolean cleanWorkDir; 045 046 @Parameter(required = true) 047 private String action; 048 049 @Parameter(required = true) 050 private String pageTemplate; 051 052 @Parameter() 053 private String siteMapDomain; 054 055 @Parameter() 056 private String drawioViewer; 057 058 @Parameter(required = false) 059 private int errors; 060 061 @Parameter() 062 private File progressOutput; 063 064 @Parameter() 065 private List<DiagramGenerator> diagramGenerators; 066 067 068// @Parameter(name = "json-progress") 069// private boolean jsonProgress; 070 071 @Parameter(defaultValue = "${project}", required = true, readonly = true) 072 MavenProject project; 073 074 /** 075 * Progress monitor reporting to a {@link PrintStream}, e.g. ``System.out``. 076 * This monitor indents sub-tasks and worked messages. It can be thought of as a hierarchical logger. 077 * @author Pavel 078 * 079 */ 080 public class PrintStreamProgressMonitor implements ProgressMonitor { 081 082 private PrintStream out; 083 private boolean closeStream; 084 private String indent; 085 protected int indentIncrement = 2; 086 private boolean cancelled; 087 088 /** 089 * Constructs a progress monitor for a given print stream. 090 * @param out 091 * @param indent Indent in spaces for this monitor. 092 * @param indentIncrement Increment to add to the indent of this monitor when constructing a sub-monitor. 093 * @param closeStream if true the monitor closes the stream in its close() method. 094 */ 095 public PrintStreamProgressMonitor(PrintStream out, int indent, int indentIncrement, boolean closeStream) { 096 this.out = out; 097 StringBuilder indentBuilder = new StringBuilder(); 098 for (int i = 0; i < indent; ++i) { 099 indentBuilder.append(' '); 100 } 101 this.indent = indentBuilder.toString(); 102 this.closeStream = closeStream; 103 } 104 105 /** 106 * Constructs a progres monitor outputting to System.out with indent 0, indentIncrement 2 and not closing the stream. 107 */ 108 public PrintStreamProgressMonitor() { 109 this(System.out, 0, 2, false); 110 } 111 112 @Override 113 public void close() { 114 if (closeStream) { 115 out.close(); 116 } 117 } 118 119 @Override 120 public boolean isCancelled() { 121 return cancelled; 122 } 123 124 @Override 125 public ProgressMonitor split(String taskName, double size, Object... data) { 126 if (isCancelled()) { 127 throw new CancellationException(); 128 } 129 out.println(indent+" "+taskName+" ("+size+")"); 130 if (data != null) { 131 for (Object d: data) { 132 out.println(formatDetail(d, indent + " ")); 133 } 134 } 135 return new PrintStreamProgressMonitor(out, indent.length()+indentIncrement, indentIncrement, false) { 136 137 @Override 138 public boolean isCancelled() { 139 return PrintStreamProgressMonitor.this.isCancelled(); 140 } 141 142 }; 143 } 144 145 /** 146 * Formats detail element for output. This implementation concatenates the indent with the detail. 147 * @param detail 148 * @param indent 149 * @return 150 */ 151 protected String formatDetail(Object detail, String indent) { 152 return indent + detail; 153 } 154 155 @Override 156 public void worked(Status status, double work, String progressMessage, Object... data) { 157 out.print(indent+" ["+status+" "+work+"] "+progressMessage); 158 if (data.length > 0) { 159 out.print(": "+Arrays.deepToString(data)); 160 } 161 out.println(); 162 if (status == Status.CANCEL) { 163 cancelled = true; 164 } 165 } 166 167 @Override 168 public ProgressMonitor setWorkRemaining(double size) { 169 // NOP 170 return this; 171 } 172 173 } 174 175 public void execute() throws MojoExecutionException { 176 177 ActionSiteGenerator actionSiteGenerator = new ActionSiteGenerator() { 178 179 @Override 180 protected Context createContext(ProgressMonitor progressMonitor) { 181 DiagramGenerator diagramGenerator; 182 if (Util.isBlank(drawioViewer)) { 183 diagramGenerator = DiagramGenerator.INSTANCE; 184 } else { 185 diagramGenerator = new DiagramGeneratorImpl() { 186 187 protected String getDrawioViewer() { 188 return drawioViewer; 189 }; 190 191 }; 192 } 193 if (diagramGenerators != null) { 194 for (DiagramGenerator dg: diagramGenerators) { 195 diagramGenerator = dg.compose(diagramGenerator); 196 } 197 } 198 return Context.singleton(DiagramGenerator.class, diagramGenerator).compose(super.createContext(progressMonitor)); 199 } 200 201 @Override 202 protected ProgressMonitor createProgressMonitor() { 203 if (progressOutput == null) { 204 return new LogProgressMonitor(getLog(), 0, 2); 205 } 206 207// if (jsonProgress) { 208// // JSON output progress monitor 209// 210// } 211 212 try { 213 return new PrintStreamProgressMonitor(new PrintStream(progressOutput), 0, 2, true); 214 } catch (FileNotFoundException e) { 215 throw new NasdanikaException(e); 216 } 217 } 218 219 }; 220 221 File baseDir = project.getBasedir(); 222 URI baseDirURI = URI.createFileURI(baseDir.getAbsolutePath()).appendSegment(""); 223 224 URI actionURI = URI.createURI(action).resolve(baseDirURI); 225 URI pageTemplateURI = URI.createURI(pageTemplate).resolve(baseDirURI); 226 227 try { 228 Map<String, Collection<String>> errors = actionSiteGenerator.generate( 229 actionURI, 230 pageTemplateURI, 231 siteMapDomain, 232 outputDirectory, 233 workDirectory, 234 cleanWorkDir); 235 236 int errorCount = 0; 237 for (Entry<String, Collection<String>> ee: errors.entrySet()) { 238 getLog().error(ee.getKey()); 239 for (String error: ee.getValue()) { 240 ++errorCount; 241 getLog().error("\t" + error); 242 } 243 } 244 if (errorCount != this.errors) { 245 throw new MojoExecutionException("There are " + errorCount + " site errors"); 246 } 247 } catch (IOException | DiagnosticException ex) { 248 throw new MojoExecutionException(ex); 249 } 250 } 251}