1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.gmavenplus.mojo;
18
19 import org.apache.maven.artifact.DependencyResolutionRequiredException;
20 import org.apache.maven.plugin.MojoExecutionException;
21 import org.apache.maven.plugin.MojoFailureException;
22 import org.apache.maven.plugins.annotations.Mojo;
23 import org.apache.maven.plugins.annotations.Parameter;
24 import org.apache.maven.plugins.annotations.ResolutionScope;
25 import org.codehaus.gmavenplus.util.NoExitSecurityManager;
26
27 import java.io.File;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.net.MalformedURLException;
31 import java.util.Set;
32
33 import static org.codehaus.gmavenplus.mojo.ExecuteMojo.GROOVY_4_0_0_RC_1;
34 import static org.codehaus.gmavenplus.util.ReflectionUtils.findConstructor;
35 import static org.codehaus.gmavenplus.util.ReflectionUtils.findField;
36 import static org.codehaus.gmavenplus.util.ReflectionUtils.findMethod;
37 import static org.codehaus.gmavenplus.util.ReflectionUtils.getField;
38 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeConstructor;
39 import static org.codehaus.gmavenplus.util.ReflectionUtils.invokeMethod;
40
41
42
43
44
45
46
47
48
49
50
51
52 @Mojo(name = "console", requiresDependencyResolution = ResolutionScope.TEST)
53 public class ConsoleMojo extends AbstractToolsMojo {
54
55
56
57
58
59
60 @Parameter(property = "consoleScript")
61 protected String consoleScript;
62
63
64
65
66
67
68
69 @Override
70 public void execute() throws MojoExecutionException, MojoFailureException {
71 try {
72 setupClassWrangler(project.getTestClasspathElements(), includeClasspath);
73 } catch (MalformedURLException e) {
74 throw new MojoExecutionException("Unable to add project test dependencies to classpath.", e);
75 } catch (DependencyResolutionRequiredException e) {
76 throw new MojoExecutionException("Test dependencies weren't resolved.", e);
77 }
78
79 logPluginClasspath();
80 classWrangler.logGroovyVersion(mojoExecution.getMojoDescriptor().getGoal());
81
82 try {
83 getLog().debug("Project test classpath:\n" + project.getTestClasspathElements());
84 } catch (DependencyResolutionRequiredException e) {
85 getLog().debug("Unable to log project test classpath");
86 }
87
88 if (groovyVersionSupportsAction()) {
89 final SecurityManager sm = System.getSecurityManager();
90 try {
91 if (!allowSystemExits) {
92 System.setSecurityManager(new NoExitSecurityManager());
93 }
94
95
96 Class<?> consoleClass;
97 try {
98 consoleClass = classWrangler.getClass("groovy.console.ui.Console");
99 } catch (ClassNotFoundException e) {
100 consoleClass = classWrangler.getClass("groovy.ui.Console");
101 }
102 Class<?> bindingClass = classWrangler.getClass("groovy.lang.Binding");
103
104
105 Object console = setupConsole(consoleClass, bindingClass);
106
107
108 invokeMethod(findMethod(consoleClass, "run"), console);
109
110
111 bindAntBuilder(consoleClass, bindingClass, console);
112
113
114 loadScript(consoleClass, console);
115
116
117 waitForConsoleClose();
118 } catch (ClassNotFoundException e) {
119 throw new MojoExecutionException("Unable to get a Groovy class from classpath (" + e.getMessage() + "). Do you have Groovy as a compile dependency in your project or the plugin?", e);
120 } catch (InvocationTargetException e) {
121 if (e.getCause() instanceof NoClassDefFoundError && "org/apache/ivy/core/report/ResolveReport".equals(e.getCause().getMessage())) {
122 throw new MojoExecutionException("Groovy 1.7.6 and 1.7.7 have a dependency on Ivy to run the console. Either change your Groovy version or add Ivy as a project or plugin dependency.", e);
123 } else {
124 throw new MojoExecutionException("Error occurred while calling a method on a Groovy class from classpath.", e);
125 }
126 } catch (IllegalAccessException e) {
127 throw new MojoExecutionException("Unable to access a method on a Groovy class from classpath.", e);
128 } catch (InstantiationException e) {
129 throw new MojoExecutionException("Error occurred while instantiating a Groovy class from classpath.", e);
130 } finally {
131 if (!allowSystemExits) {
132 System.setSecurityManager(sm);
133 }
134 }
135 } else {
136 getLog().error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support running a console. The minimum version of Groovy required is " + minGroovyVersion + ". Skipping console startup.");
137 }
138 }
139
140 protected void loadScript(Class<?> consoleClass, Object console) throws InvocationTargetException, IllegalAccessException {
141 if (consoleScript != null) {
142 Method loadScriptFile = findMethod(consoleClass, "loadScriptFile", File.class);
143 File consoleScriptFile = new File(consoleScript);
144 if (consoleScriptFile.isFile()) {
145 invokeMethod(loadScriptFile, console, consoleScriptFile);
146 } else if (project.getProperties().containsKey(consoleScript)) {
147 consoleScriptFile = new File(project.getProperties().getProperty(consoleScript));
148 if (consoleScriptFile.isFile()) {
149 invokeMethod(loadScriptFile, console, consoleScriptFile);
150 } else {
151 getLog().warn("consoleScript ('" + consoleScript + "') doesn't exist in project properties or as a file.");
152 }
153 } else {
154 getLog().warn("consoleScript ('" + consoleScript + "') doesn't exist in project properties or as a file.");
155 }
156 }
157 }
158
159
160
161
162
163
164
165
166
167
168
169 protected Object setupConsole(final Class<?> consoleClass, final Class<?> bindingClass) throws InvocationTargetException, IllegalAccessException, InstantiationException {
170 Object binding = invokeConstructor(findConstructor(bindingClass));
171 initializeProperties();
172 Method setVariable = findMethod(bindingClass, "setVariable", String.class, Object.class);
173 if (bindPropertiesToSeparateVariables) {
174 for (Object k : properties.keySet()) {
175 invokeMethod(setVariable, binding, k, properties.get(k));
176 }
177 } else {
178 if (groovyOlderThan(GROOVY_4_0_0_RC_1)) {
179 invokeMethod(setVariable, binding, "properties", properties);
180 } else {
181 throw new IllegalArgumentException("properties is a read-only property in Groovy " + GROOVY_4_0_0_RC_1 + " and later.");
182 }
183 }
184
185 return invokeConstructor(findConstructor(consoleClass, ClassLoader.class, bindingClass), classWrangler.getClassLoader(), binding);
186 }
187
188
189
190
191
192
193
194
195
196
197
198 protected void bindAntBuilder(Class<?> consoleClass, Class<?> bindingClass, Object console) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
199 if (properties.containsKey("ant")) {
200 Class<?> groovyShellClass = classWrangler.getClass("groovy.lang.GroovyShell");
201 Object shell = getField(findField(consoleClass, "shell", groovyShellClass), console);
202 Object binding = invokeMethod(findMethod(groovyShellClass, "getContext"), shell);
203 Object antBuilder = null;
204 try {
205 antBuilder = invokeConstructor(findConstructor(classWrangler.getClass("groovy.ant.AntBuilder")));
206 } catch (ClassNotFoundException e1) {
207 getLog().debug("groovy.ant.AntBuilder not available, trying groovy.util.AntBuilder.");
208 try {
209 antBuilder = invokeConstructor(findConstructor(classWrangler.getClass("groovy.util.AntBuilder")));
210 } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | InstantiationException e2) {
211 logUnableToInitializeAntBuilder(e2);
212 }
213 } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
214 logUnableToInitializeAntBuilder(e);
215 }
216 if (antBuilder != null) {
217 if (bindPropertiesToSeparateVariables) {
218 invokeMethod(findMethod(bindingClass, "setVariable", String.class, Object.class), binding, "ant", antBuilder);
219 } else {
220 properties.put("ant", antBuilder);
221 }
222 }
223 }
224 }
225
226
227
228
229
230
231 protected void waitForConsoleClose() throws MojoFailureException {
232 Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
233 Thread[] threadArray = threadSet.toArray(new Thread[0]);
234 Thread consoleThread = null;
235 for (Thread thread : threadArray) {
236 if ("AWT-Shutdown".equals(thread.getName())) {
237 consoleThread = thread;
238 break;
239 }
240 }
241 if (consoleThread != null) {
242 try {
243 consoleThread.join();
244 } catch (InterruptedException e) {
245 throw new MojoFailureException("Mojo interrupted while waiting for Console thread to end.", e);
246 }
247 } else {
248 throw new MojoFailureException("Unable to locate Console thread to wait on.");
249 }
250 }
251
252 }