1 package net.sf.mvnflexreports;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.FileNotFoundException;
6 import java.util.ArrayList;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Locale;
10 import java.util.Map;
11 import java.util.ResourceBundle;
12 import java.util.Set;
13 import java.util.TreeMap;
14
15 import javax.xml.namespace.QName;
16 import javax.xml.stream.XMLInputFactory;
17 import javax.xml.stream.XMLStreamConstants;
18 import javax.xml.stream.XMLStreamException;
19 import javax.xml.stream.XMLStreamReader;
20
21 import org.apache.maven.doxia.siterenderer.Renderer;
22 import org.apache.maven.project.MavenProject;
23 import org.apache.maven.reporting.MavenReportException;
24
25 /***
26 * @author Rémi Flament
27 * @goal remoteobject-maven-report
28 * @phase site
29 */
30 public class RemoteObjectMavenReport extends AbstractGraphvizMavenReport {
31
32 /***
33 * The output directory for the final HTML report. Note that this parameter
34 * is only evaluated if the goal is run directly from the command line or
35 * during the default lifecycle. If the goal is run indirectly as part of a
36 * site generation, the output directory configured in the Maven Site Plugin
37 * is used instead.
38 *
39 * @parameter expression="${project.reporting.outputDirectory}"
40 * @required
41 */
42 protected File outputDirectory;
43
44 /***
45 * The project to analyse.
46 *
47 * @parameter expression="${project}"
48 * @required
49 * @readonly
50 */
51 protected MavenProject project;
52
53 /***
54 * The directory containing source code to parse.
55 *
56 * @parameter expression="${basedir}/src/main/flex"
57 * @required
58 */
59 private File sourceDir;
60
61 /***
62 * The layout to use. This parameter will be used as the rankdir parameter.
63 *
64 * @parameter expression="TB"
65 */
66 protected String remoteObjectLayout;
67
68 /***
69 * @parameter
70 */
71 private Set<String> remoteObjectPatterns;
72
73 /***
74 * @parameter
75 */
76 private Set<String> remoteMethodPatterns;
77
78 /***
79 * The fill color for remote objects in the graphical report
80 *
81 * @parameter expression="cornflowerblue"
82 */
83 private String remoteObjectColor;
84
85 /***
86 * The fill color for mxml components in the graphical report
87 *
88 * @parameter expression="firebrick1"
89 */
90 private String mxmlComponentColor;
91
92 /***
93 * Site rendering component for generating the HTML report.
94 *
95 * @component
96 */
97 private Renderer siteRenderer;
98
99 protected void executeReport(Locale locale) throws MavenReportException {
100
101 if (remoteObjectPatterns == null) {
102 remoteObjectPatterns = new HashSet<String>();
103 }
104
105 if (remoteMethodPatterns == null) {
106 remoteMethodPatterns = new HashSet<String>();
107 }
108
109 if (remoteObjectPatterns.size() == 0) {
110 remoteObjectPatterns.add("RemoteObject");
111 }
112
113 if (remoteMethodPatterns.size() == 0) {
114 remoteMethodPatterns.add("method");
115 }
116
117 List<File> files = new ArrayList<File>();
118 getFiles(sourceDir.getAbsoluteFile(), files, ".as", ".mxml");
119 ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
120
121 try {
122 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
123 Map<String, RemoteObject> remoteObjects = new TreeMap<String, RemoteObject>();
124 Map<String, MXMLComponent> components = new TreeMap<String, MXMLComponent>();
125 for (File sourceFile : files) {
126 getLog().debug("Processing flex source file " + sourceFile.getCanonicalPath());
127 findRemoteObjects(sourceFile, remoteObjects, components);
128 }
129
130 RemoteObjectReportGenerator generator = new RemoteObjectReportGenerator(getSink());
131 generator.setMxmlComponentColor(mxmlComponentColor);
132 generator.setRemoteObjectColor(remoteObjectColor);
133 generator.setFontName(fontName);
134 generator.setFontSize(fontSize);
135 generator.setProgramName(programName);
136 generator.setLayout(remoteObjectLayout);
137 getLog().debug("mxmlComponentColor = " + mxmlComponentColor);
138 getLog().debug("remoteObjectColor = " + remoteObjectColor);
139 generator.generate(remoteObjects.values(), components.values(), this.getReportOutputDirectory(), getLog());
140
141 } catch (Exception e) {
142 throw new MavenReportException(e.getMessage(), e);
143 } finally {
144 Thread.currentThread().setContextClassLoader(origLoader);
145 }
146
147 }
148
149 private void findRemoteObjects(File file, Map<String, RemoteObject> remoteObjects, Map<String, MXMLComponent> components) throws FileNotFoundException, XMLStreamException {
150
151 getLog().debug("getUsedRemoteObjects() for file " + file.getAbsolutePath());
152
153 MXMLComponent currentComponent = null;
154
155 if (file.getName().toLowerCase().endsWith(".mxml")) {
156
157 currentComponent = components.get(file.getName());
158 if (currentComponent == null) {
159 currentComponent = new MXMLComponent();
160 currentComponent.setFilename(file.getName());
161 components.put(file.getName(), currentComponent);
162 }
163
164 XMLInputFactory factory = XMLInputFactory.newInstance();
165 XMLStreamReader parser = factory.createXMLStreamReader(new FileInputStream(file));
166
167 RemoteObject currentRemoteObject = null;
168 RemoteObjectUse currentRemoteObjectUse = null;
169 while (true) {
170 int event = parser.next();
171 if (event == XMLStreamConstants.END_DOCUMENT) {
172 parser.close();
173 break;
174 }
175 if (event == XMLStreamConstants.START_ELEMENT) {
176
177 if (remoteObjectPatterns.contains(parser.getLocalName())) {
178
179 String destination = null;
180 String id = null;
181 String type = parser.getLocalName();
182 for (int i = 0; i < parser.getAttributeCount(); i++) {
183 QName localName = parser.getAttributeName(i);
184 if (localName.getLocalPart().equals("destination")) {
185
186 destination = parser.getAttributeValue(i);
187 getLog().debug(file.getAbsolutePath() + " uses remote object " + destination);
188
189 currentRemoteObject = remoteObjects.get(destination);
190 if (currentRemoteObject == null) {
191 currentRemoteObject = new RemoteObject();
192 currentRemoteObject.setDestination(destination);
193
194 remoteObjects.put(destination, currentRemoteObject);
195 }
196 currentRemoteObject.increment();
197
198 }
199
200 if (localName.getLocalPart().equals("id")) {
201 id = parser.getAttributeValue(i);
202 }
203
204 }
205
206 if (id != null && destination != null) {
207 currentRemoteObjectUse = currentComponent.getUsedRemoteObjects().get(destination + "#" + id);
208 if (currentRemoteObjectUse == null) {
209 currentRemoteObjectUse = new RemoteObjectUse();
210 currentRemoteObjectUse.setDestination(destination);
211 currentRemoteObjectUse.setRemoteObject(currentRemoteObject);
212 currentRemoteObjectUse.setId(id);
213 currentRemoteObjectUse.setRemoteObjectType(type);
214 currentComponent.getUsedRemoteObjects().put(destination + "#" + id, currentRemoteObjectUse);
215 }
216 currentRemoteObjectUse.setComponent(currentComponent);
217 }
218
219 } else if (remoteMethodPatterns.contains(parser.getLocalName()) && currentRemoteObject != null) {
220 for (int i = 0; i < parser.getAttributeCount(); i++) {
221 QName localName = parser.getAttributeName(i);
222 if (localName.getLocalPart().equals("name")) {
223
224 String methodName = parser.getAttributeValue(i);
225 getLog().debug(file.getAbsolutePath() + " uses method " + methodName + " on remote object " + currentRemoteObject.getDestination());
226 RemoteObjectMethod method = currentRemoteObject.getMethods().get(methodName);
227 if (method == null) {
228 method = new RemoteObjectMethod();
229 method.setName(methodName);
230
231 currentRemoteObject.getMethods().put(methodName, method);
232 }
233
234 method.increment();
235 if (currentRemoteObjectUse != null) {
236 currentRemoteObjectUse.getUsedMethods().add(method);
237 }
238 }
239 }
240 }
241 }
242
243 }
244
245 } else if (file.getName().toLowerCase().endsWith(".as")) {
246 getLog().debug("ignoring " + file.getAbsolutePath() + " : not implemented yet");
247 } else {
248 getLog().info("ignoring " + file.getAbsolutePath() + " because we don't know how to search remote objects in it.");
249 }
250
251 }
252
253 /***
254 * @return Returns the sourceDir.
255 */
256 public File getSourceDir() {
257 return sourceDir;
258 }
259
260 /***
261 * @param sourceDir
262 * The sourceDir to set.
263 */
264 public void setSourceDir(File sourceDir) {
265 this.sourceDir = sourceDir;
266 }
267
268 protected String getOutputDirectory() {
269 return outputDirectory.getAbsolutePath();
270
271 }
272
273 protected MavenProject getProject() {
274 return project;
275 }
276
277 protected Renderer getSiteRenderer() {
278 return siteRenderer;
279 }
280
281 public String getDescription(Locale locale) {
282 return getBundle(locale).getString("report.remoteobject-flex-maven.name");
283
284 }
285
286 public String getName(Locale locale) {
287 return getBundle(locale).getString("report.remoteobject-flex-maven.name");
288
289 }
290
291 private static ResourceBundle getBundle(Locale locale) {
292 return ResourceBundle.getBundle("remoteobject-maven-report", locale, RemoteObjectMavenReport.class.getClassLoader());
293 }
294
295 public String getOutputName() {
296 return "remoteobject-maven-report";
297 }
298
299 public Set<String> getRemoteObjectPatterns() {
300 return remoteObjectPatterns;
301 }
302
303 public void setRemoteObjectPatterns(Set<String> remoteObjectPatterns) {
304 this.remoteObjectPatterns = remoteObjectPatterns;
305 }
306
307 public Set<String> getRemoteMethodPatterns() {
308 return remoteMethodPatterns;
309 }
310
311 public void setRemoteMethodPatterns(Set<String> remoteMethodPatterns) {
312 this.remoteMethodPatterns = remoteMethodPatterns;
313 }
314
315 public String getRemoteObjectColor() {
316 return remoteObjectColor;
317 }
318
319 public void setRemoteObjectColor(String remoteObjectColor) {
320 this.remoteObjectColor = remoteObjectColor;
321 }
322
323 public String getMxmlComponentColor() {
324 return mxmlComponentColor;
325 }
326
327 public void setMxmlComponentColor(String mxmlComponentColor) {
328 this.mxmlComponentColor = mxmlComponentColor;
329 }
330
331 public String getRemoteObjectLayout() {
332 return remoteObjectLayout;
333 }
334
335 public void setRemoteObjectLayout(String remoteObjectLayout) {
336 this.remoteObjectLayout = remoteObjectLayout;
337 }
338
339 }