Skip to content

Commit e68a536

Browse files
committed
Merge pull request #222 from scijava/custom-main-class
Add support for custom main classes
2 parents 5a1632b + c2c87f3 commit e68a536

File tree

8 files changed

+452
-1
lines changed

8 files changed

+452
-1
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111

1212
<artifactId>scijava-common</artifactId>
13-
<version>2.50.2-SNAPSHOT</version>
13+
<version>2.51.0-SNAPSHOT</version>
1414

1515
<name>SciJava Common</name>
1616
<description>SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by both ImageJ and SCIFIO.</description>

src/main/java/org/scijava/AbstractGateway.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.scijava.io.IOService;
4646
import org.scijava.io.RecentFileService;
4747
import org.scijava.log.LogService;
48+
import org.scijava.main.MainService;
4849
import org.scijava.menu.MenuService;
4950
import org.scijava.module.ModuleService;
5051
import org.scijava.object.ObjectService;
@@ -163,6 +164,11 @@ public LogService log() {
163164
return get(LogService.class);
164165
}
165166

167+
@Override
168+
public MainService main() {
169+
return get(MainService.class);
170+
}
171+
166172
@Override
167173
public MenuService menu() {
168174
return get(MenuService.class);

src/main/java/org/scijava/Gateway.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.scijava.io.IOService;
4444
import org.scijava.io.RecentFileService;
4545
import org.scijava.log.LogService;
46+
import org.scijava.main.MainService;
4647
import org.scijava.menu.MenuService;
4748
import org.scijava.module.ModuleService;
4849
import org.scijava.object.ObjectService;
@@ -226,6 +227,13 @@ public interface Gateway extends RichPlugin, Versioned {
226227
*/
227228
LogService log();
228229

230+
/**
231+
* Gets this application context's {@link MainService}.
232+
*
233+
* @return The {@link MainService} of this application context.
234+
*/
235+
MainService main();
236+
229237
/**
230238
* Gets this application context's {@link MenuService}.
231239
*
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2015 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.main;
33+
34+
import java.lang.reflect.InvocationTargetException;
35+
import java.lang.reflect.Method;
36+
import java.util.ArrayList;
37+
import java.util.List;
38+
39+
import org.scijava.log.LogService;
40+
import org.scijava.plugin.Parameter;
41+
import org.scijava.plugin.Plugin;
42+
import org.scijava.service.AbstractService;
43+
import org.scijava.service.Service;
44+
import org.scijava.util.ClassUtils;
45+
46+
/**
47+
* Default implementation of {@link MainService}.
48+
*
49+
* @author Curtis Rueden
50+
*/
51+
@Plugin(type = Service.class)
52+
public class DefaultMainService extends AbstractService implements MainService {
53+
54+
@Parameter(required = false)
55+
private LogService log;
56+
57+
private final List<Main> mains = new ArrayList<Main>();
58+
59+
@Override
60+
public int execMains() {
61+
int mainCount = 0;
62+
for (final Main main : mains) {
63+
main.exec();
64+
mainCount++;
65+
}
66+
return mainCount;
67+
}
68+
69+
@Override
70+
public void addMain(final String className, final String... args) {
71+
mains.add(new DefaultMain(className, args));
72+
}
73+
74+
@Override
75+
public Main[] getMains() {
76+
return mains.toArray(new Main[mains.size()]);
77+
}
78+
79+
// -- Helper classes --
80+
81+
/** Default implementation of {@link MainService.Main}. */
82+
private class DefaultMain implements Main {
83+
private String className;
84+
private String[] args;
85+
86+
public DefaultMain(final String className, final String... args) {
87+
this.className = className;
88+
this.args = args.clone();
89+
}
90+
91+
@Override
92+
public String className() {
93+
return className;
94+
}
95+
96+
@Override
97+
public String[] args() {
98+
return args;
99+
}
100+
101+
@Override
102+
public void exec() {
103+
try {
104+
final Class<?> mainClass = ClassUtils.loadClass(className);
105+
final Method main = mainClass.getMethod("main", String[].class);
106+
main.invoke(null, new Object[] { args });
107+
}
108+
catch (final NoSuchMethodException exc) {
109+
if (log != null) {
110+
log.error("No main method for class: " + className, exc);
111+
}
112+
}
113+
catch (final IllegalAccessException exc) {
114+
if (log != null) log.error(exc);
115+
}
116+
catch (final InvocationTargetException exc) {
117+
if (log != null) log.error(exc);
118+
}
119+
}
120+
}
121+
122+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2015 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.main;
33+
34+
import org.scijava.service.SciJavaService;
35+
36+
/**
37+
* Interface for services which manage dynamic execution of main methods.
38+
*
39+
* @author Curtis Rueden
40+
*/
41+
public interface MainService extends SciJavaService {
42+
43+
/**
44+
* Executes registered main classes, in the order they were registered.
45+
*
46+
* @return The number of main methods which were executed.
47+
*/
48+
int execMains();
49+
50+
/** Registers a main class to be executed by {@link #execMains()}. */
51+
void addMain(final String className, final String... args);
52+
53+
/** Gets the registered main classes to execute. */
54+
Main[] getMains();
55+
56+
/** Data structure containing main class and argument values. */
57+
interface Main {
58+
59+
/** Gets the name of the class containing the {@code main} method to run. */
60+
String className();
61+
62+
/** Gets the arguments to pass to the class's {@code main} method. */
63+
String[] args();
64+
65+
/** Runs the {@code main} method with the associated arguments. */
66+
void exec();
67+
}
68+
69+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2015 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.main.console;
33+
34+
import java.util.ArrayList;
35+
import java.util.LinkedList;
36+
import java.util.List;
37+
38+
import org.scijava.console.AbstractConsoleArgument;
39+
import org.scijava.console.ConsoleArgument;
40+
import org.scijava.log.LogService;
41+
import org.scijava.main.MainService;
42+
import org.scijava.plugin.Parameter;
43+
import org.scijava.plugin.Plugin;
44+
45+
/**
46+
* Handles the {@code --main} command line argument, which launches an
47+
* alternative main class.
48+
*
49+
* @author Curtis Rueden
50+
*/
51+
@Plugin(type = ConsoleArgument.class)
52+
public class MainArgument extends AbstractConsoleArgument {
53+
54+
@Parameter(required = false)
55+
private MainService mainService;
56+
57+
@Parameter(required = false)
58+
private LogService log;
59+
60+
// -- ConsoleArgument methods --
61+
62+
@Override
63+
public void handle(final LinkedList<String> args) {
64+
if (!supports(args)) return;
65+
66+
args.removeFirst(); // --main / --main-class
67+
final String className = args.removeFirst();
68+
69+
final List<String> argList = new ArrayList<String>();
70+
while (!args.isEmpty() && !isMainFlag(args) && !isSeparator(args)) {
71+
argList.add(args.removeFirst());
72+
}
73+
if (isSeparator(args)) args.removeFirst(); // remove the -- separator
74+
final String[] mainArgs = argList.toArray(new String[argList.size()]);
75+
76+
mainService.addMain(className, mainArgs);
77+
}
78+
79+
// -- Typed methods --
80+
81+
@Override
82+
public boolean supports(final LinkedList<String> args) {
83+
return mainService != null && isMainFlag(args);
84+
}
85+
86+
// -- Helper methods --
87+
88+
private boolean isMainFlag(final LinkedList<String> args) {
89+
if (args == null || args.isEmpty()) return false;
90+
final String arg = args.getFirst();
91+
return arg.equals("--main") || arg.equals("--main-class");
92+
}
93+
94+
private boolean isSeparator(final LinkedList<String> args) {
95+
if (args == null || args.isEmpty()) return false;
96+
return args.getFirst().equals("--");
97+
}
98+
99+
}

src/test/java/org/scijava/console/ConsoleServiceTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ public void handle(final LinkedList<String> args) {
220220
argsHandled = true;
221221
}
222222

223+
@Override
224+
public boolean supports(final LinkedList<String> args) {
225+
return !args.isEmpty() && args.getFirst().equals("--foo");
226+
}
223227
}
224228

225229
private static class OutputTracker implements OutputListener {

0 commit comments

Comments
 (0)