|
40 | 40 | import java.util.HashMap;
|
41 | 41 | import java.util.List;
|
42 | 42 | import java.util.Map;
|
| 43 | +import java.util.Objects; |
| 44 | +import java.util.concurrent.CopyOnWriteArrayList; |
43 | 45 |
|
44 | 46 | import javax.script.Invocable;
|
45 | 47 | import javax.script.ScriptContext;
|
@@ -152,6 +154,15 @@ public class ExtensionScript extends ExtensionAdaptor implements CommandLineList
|
152 | 154 | */
|
153 | 155 | private List<File> trackedDirs = Collections.synchronizedList(new ArrayList<>());
|
154 | 156 |
|
| 157 | + /** |
| 158 | + * The script output listeners added to the extension. |
| 159 | + * |
| 160 | + * @see #addScriptOutputListener(ScriptOutputListener) |
| 161 | + * @see #invokeScriptImpl(ScriptWrapper) |
| 162 | + * @see #removeScriptOutputListener(ScriptOutputListener) |
| 163 | + */ |
| 164 | + private List<ScriptOutputListener> outputListeners = new CopyOnWriteArrayList<>(); |
| 165 | + |
155 | 166 | public ExtensionScript() {
|
156 | 167 | super(NAME);
|
157 | 168 | this.setOrder(EXTENSION_ORDER);
|
@@ -1191,17 +1202,16 @@ public List<ScriptWrapper> getTemplates(ScriptType type) {
|
1191 | 1202 | * ever script. It also supports script specific writers.
|
1192 | 1203 | */
|
1193 | 1204 | private Writer getWriters(ScriptWrapper script) {
|
| 1205 | + Writer delegatee = this.writers; |
1194 | 1206 | Writer writer = script.getWriter();
|
1195 |
| - if (writer == null) { |
1196 |
| - // No script specific writer, just return the std one |
1197 |
| - return this.writers; |
1198 |
| - } else { |
1199 |
| - // Return the script specific writer in addition to the std one |
| 1207 | + if (writer != null) { |
| 1208 | + // Use the script specific writer in addition to the std one |
1200 | 1209 | MultipleWriters scriptWriters = new MultipleWriters();
|
1201 | 1210 | scriptWriters.addWriter(writer);
|
1202 | 1211 | scriptWriters.addWriter(writers);
|
1203 |
| - return scriptWriters; |
| 1212 | + delegatee = scriptWriters; |
1204 | 1213 | }
|
| 1214 | + return new ScriptWriter(script, delegatee, outputListeners); |
1205 | 1215 | }
|
1206 | 1216 |
|
1207 | 1217 | /**
|
@@ -1609,14 +1619,53 @@ public void removeListener(ScriptEventListener listener) {
|
1609 | 1619 | this.listeners.remove(listener);
|
1610 | 1620 | }
|
1611 | 1621 |
|
| 1622 | + /** |
| 1623 | + * Adds the given writer. |
| 1624 | + * <p> |
| 1625 | + * It will be written to each time a script writes some output. |
| 1626 | + * |
| 1627 | + * @param writer the writer to add. |
| 1628 | + * @see #removeWriter(Writer) |
| 1629 | + * @see #addScriptOutputListener(ScriptOutputListener) |
| 1630 | + */ |
1612 | 1631 | public void addWriter(Writer writer) {
|
1613 | 1632 | this.writers.addWriter(writer);
|
1614 | 1633 | }
|
1615 | 1634 |
|
| 1635 | + /** |
| 1636 | + * Removes the given writer. |
| 1637 | + * |
| 1638 | + * @param writer the writer to remove. |
| 1639 | + * @see #addWriter(Writer) |
| 1640 | + */ |
1616 | 1641 | public void removeWriter(Writer writer) {
|
1617 | 1642 | this.writers.removeWriter(writer);
|
1618 | 1643 | }
|
1619 | 1644 |
|
| 1645 | + /** |
| 1646 | + * Adds the given script output listener. |
| 1647 | + * |
| 1648 | + * @param listener the listener to add. |
| 1649 | + * @since TODO add version |
| 1650 | + * @throws NullPointerException if the given listener is {@code null}. |
| 1651 | + * @see #removeScriptOutputListener(ScriptOutputListener) |
| 1652 | + */ |
| 1653 | + public void addScriptOutputListener(ScriptOutputListener listener) { |
| 1654 | + outputListeners.add(Objects.requireNonNull(listener, "The parameter listener must not be null.")); |
| 1655 | + } |
| 1656 | + |
| 1657 | + /** |
| 1658 | + * Removes the given script output listener. |
| 1659 | + * |
| 1660 | + * @param listener the listener to remove. |
| 1661 | + * @since TODO add version |
| 1662 | + * @throws NullPointerException if the given listener is {@code null}. |
| 1663 | + * @see #addScriptOutputListener(ScriptOutputListener) |
| 1664 | + */ |
| 1665 | + public void removeScriptOutputListener(ScriptOutputListener listener) { |
| 1666 | + outputListeners.remove(Objects.requireNonNull(listener, "The parameter listener must not be null.")); |
| 1667 | + } |
| 1668 | + |
1620 | 1669 | public ScriptUI getScriptUI() {
|
1621 | 1670 | return scriptUI;
|
1622 | 1671 | }
|
@@ -1852,4 +1901,39 @@ public void sessionModeChanged(Mode mode) {
|
1852 | 1901 | }
|
1853 | 1902 |
|
1854 | 1903 | }
|
| 1904 | + |
| 1905 | + /** |
| 1906 | + * A {@code Writer} that notifies {@link ScriptOutputListener}s when writing. |
| 1907 | + */ |
| 1908 | + private static class ScriptWriter extends Writer { |
| 1909 | + |
| 1910 | + private final ScriptWrapper script; |
| 1911 | + private final Writer delegatee; |
| 1912 | + private final List<ScriptOutputListener> outputListeners; |
| 1913 | + |
| 1914 | + public ScriptWriter(ScriptWrapper script, Writer delegatee, List<ScriptOutputListener> outputListeners) { |
| 1915 | + this.script = Objects.requireNonNull(script); |
| 1916 | + this.delegatee = Objects.requireNonNull(delegatee); |
| 1917 | + this.outputListeners = Objects.requireNonNull(outputListeners); |
| 1918 | + } |
| 1919 | + |
| 1920 | + @Override |
| 1921 | + public void write(char[] cbuf, int off, int len) throws IOException { |
| 1922 | + delegatee.write(cbuf, off, len); |
| 1923 | + if (!outputListeners.isEmpty()) { |
| 1924 | + String output = new String(cbuf, off, len); |
| 1925 | + outputListeners.forEach(e -> e.output(script, output)); |
| 1926 | + } |
| 1927 | + } |
| 1928 | + |
| 1929 | + @Override |
| 1930 | + public void flush() throws IOException { |
| 1931 | + delegatee.flush(); |
| 1932 | + } |
| 1933 | + |
| 1934 | + @Override |
| 1935 | + public void close() throws IOException { |
| 1936 | + delegatee.close(); |
| 1937 | + } |
| 1938 | + } |
1855 | 1939 | }
|
0 commit comments