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