This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 7ad7021f800b01581fd523b3ff62eded1e7eb94c
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Nov 29 11:26:54 2023 +0100

    Add a "sis-shell" command for launching jshell with Apache SIS libraries.
    It implies adding a `SIS` static class for easy invocations from JShell.
---
 .../main/org/apache/sis/console/SIS.java           | 754 +++++++++++++++++++++
 .../src/org.apache.sis.gui/bundle/bin/sis_shell    |  29 +
 .../org.apache.sis.gui/bundle/bin/sis_shell.bat    |  25 +
 .../src/org.apache.sis.gui/bundle/conf/imports.jsh | 299 ++++++++
 4 files changed, 1107 insertions(+)

diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/SIS.java 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/SIS.java
new file mode 100644
index 0000000000..2f78e06b7e
--- /dev/null
+++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/SIS.java
@@ -0,0 +1,754 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.console;
+
+import java.util.EnumMap;
+import java.io.PrintWriter;
+import org.apache.sis.io.wkt.Colors;
+import org.apache.sis.util.Static;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.internal.X364;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.io.wkt.WKTFormat;
+
+
+/**
+ * Entry point for {@code SIS} commands from JShell.
+ * This class provides the same commands than the {@code SIS} shell script, 
but from Java code.
+ * Each method accepts an arbitrary number of arguments of type {@link Object}.
+ * The actual argument values should be instances of {@link String},
+ * but the arguments that are input or output files can also be instances of
+ * {@link java.io.File}, {@link java.nio.file.Path}, {@link java.net.URL}, 
{@link java.net.URI}
+ * or any other type recognized by {@link 
org.apache.sis.storage.StorageConnector}.
+ *
+ * <p>This class should not be used in Java applications.
+ * This class is provided for usage in JShell environment.</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.5
+ * @since   1.5
+ */
+public final class SIS extends Static {
+    /*
+     * Usages of `Console#writer()` within JShell seems incompatible with 
JShell own writer.
+     * Problems observed with Java 21 on Linux when printing non-ASCII 
characters.
+     */
+    static {
+        CommandRunner.avoidConsoleWriter();
+    }
+
+    /**
+     * Builder for calls to the SIS command-line. Each sub-command is 
represented by a subclasses of {@code Builder}.
+     * A unique instance for each command is provided as fields in {@link 
SIS}, and that instance is cloned when the
+     * user wants to add options.
+     *
+     * @param  <C>  the sub-class for the command builder.
+     */
+    private static abstract class Builder<C extends Builder<C>> implements 
Cloneable {
+        /**
+         * Name of the sub-command. Shall be one of the names recognized by 
{@link Command}.
+         */
+        private final String command;
+
+        /**
+         * The options added by the user, or {@code null} if this instance is 
a field of the {@link SIS} class.
+         * In the latter case, this builder shall be considered immutable and 
options shall be added in a clone.
+         */
+        private EnumMap<Option,Object> options;
+
+        /**
+         * Creates a new builder for an immutable instance to be assigned to a 
{@code SIS} field.
+         *
+         * @param  command  name of the sub-command. Shall be one of the names 
recognized by {@link Command}.
+         */
+        Builder(final String command) {
+            this.command = command;
+        }
+
+        /**
+         * Sets the value of an option.
+         *
+         * @param  key    the option.
+         * @param  value  value for the specified option.
+         * @return the builder on which to perform chained method calls.
+         */
+        @SuppressWarnings({"unchecked", "null"})
+        final C set(final Option key, Object value) {
+            if (key.hasValue && (value = trim(value)) == null) {
+                final String option = key.label();
+                throw new 
IllegalArgumentException(Errors.format(Errors.Keys.MissingValueForOption_1, 
option));
+            }
+            Builder<C> target = this;
+            if (options == null) try {
+                target = (Builder<C>) clone();
+                target.options = new EnumMap<>(Option.class);
+            } catch (CloneNotSupportedException e) {
+                throw new AssertionError(e);
+            }
+            target.options.put(key, value);
+            return (C) target;
+        }
+
+        /**
+         * If the given value is a character string, trims it and returns 
either a non-empty string or null.
+         * Otherwise returns the value unchanged.
+         */
+        private static Object trim(final Object value) {
+            if (value instanceof CharSequence) {
+                final String s = value.toString().trim();
+                return s.isBlank() ? null : s;
+            }
+            return value;
+        }
+
+        /**
+         * Prints full stack trace in case of failure.
+         *
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public C debug() {
+            return set(Option.DEBUG, null);
+        }
+
+        /**
+         * Lists the options available for the sub-command.
+         *
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public C help() {
+            return set(Option.HELP, null);
+        }
+
+        /**
+         * Executes the command with the given arguments. The arguments are 
usually {@link String} instances,
+         * but may also be instances of {@link java.io.File}, {@link 
java.nio.file.Path}, {@link java.net.URL},
+         * {@link java.net.URI} or other types accepted by {@link 
org.apache.sis.storage.StorageConnector} if
+         * the corresponding argument specifies an input or output.
+         *
+         * @param  name  name of the sub-command to execute.
+         * @param  args  the arguments to pass to the sub-command.
+         * @throws Exception if an error occurred while executing the command.
+         */
+        @SuppressWarnings("UseOfSystemOutOrSystemErr")
+        public void run(final Object... args) throws Exception {
+            /*
+             * Count the number of arguments to insert at the beginning,
+             * including the argument for the sub-command name.
+             */
+            int i = 1;
+            if (options != null) {
+                for (Option key : options.keySet()) {
+                    i += (key.hasValue ? 2 : 1);
+                }
+            }
+            /*
+             * Copy the sub-command name, the options, then the arguments 
specified to this method.
+             */
+            final var allArgs = new Object[args.length + i];
+            i = 0;
+            allArgs[i++] = command;
+            if (options != null) {
+                for (final EnumMap.Entry<Option,Object> entry : 
options.entrySet()) {
+                    final Option key = entry.getKey();
+                    allArgs[i++] = Option.PREFIX.concat(key.label());
+                    if (key.hasValue) {
+                        allArgs[i++] = entry.getValue();
+                    }
+                }
+            }
+            System.arraycopy(args, 0, allArgs, i, args.length);
+            /*
+             * Prints an echo of the command to execute, then execute.
+             * The operation may fail without throwing an exception.
+             */
+            var c = new Command(allArgs);
+            final PrintWriter out = c.writer(false);
+            out.print("> sis");
+            for (i=0; i < allArgs.length; i++) {
+                final String arg = allArgs[i].toString();
+                final int start = arg.startsWith(Option.PREFIX) ? 
Option.PREFIX.length() : 0;
+                final boolean quote = 
!CharSequences.isUnicodeIdentifier(arg.substring(start));
+                out.print(' ');
+                if (quote) out.print('"');
+                out.print(arg.replace("\"", "\\\""));
+                if (quote) out.print('"');
+            }
+            out.println();
+            int status = c.run();
+            if (status != 0) {
+                c.writer(true).println("Error code " + status);
+            }
+        }
+
+        /**
+         * {@return the command with all options that have been set}.
+         */
+        @Override
+        public String toString() {
+            if (options == null) return command;
+            final var sb = new StringBuilder(command);
+            options.forEach((key, value) -> sb.append(' 
').append(Option.PREFIX).append(key.label()).append(' ').append(value));
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private SIS() {
+    }
+
+
+
+
+    /**
+     * Shows a help overview.
+     * This sub-command prints the same text than when {@code SIS} is invoked 
on the command-line without arguments.
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     SIS.HELP.run();
+     *     }
+     */
+    public static final Help HELP = new Help();
+
+    /**
+     * Builder for the "help" sub-command. This builder provides convenience 
methods
+     * for setting options before to execute the command by a call to {@link 
#run(Object...)}.
+     *
+     * @see #HELP
+     */
+    public static final class Help extends Builder<Help> {
+        /** Creates the unique instance. */
+        Help() {super("help");}
+
+        /**
+         * Sets the locale to use for the command output.
+         *
+         * @param  value  the language and country code.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Help locale(String value) {
+            return set(Option.LOCALE, value);
+        }
+
+        /**
+         * Sets encoding to use for the command outputs.
+         * This option rarely needs to be specified.
+         *
+         * @param  value  the character set name.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Help encoding(String value) {
+            return set(Option.ENCODING, value);
+        }
+    }
+
+
+
+
+    /**
+     * Shows information about Apache SIS and system configuration.
+     * By default this sub-command prints all information except the section 
about dependencies.
+     * Some available options are:
+     *
+     * <ul>
+     *   <li>{@code --brief}:   prints only Apache SIS version number.</li>
+     *   <li>{@code --verbose}: prints all information including the 
libraries.</li>
+     * </ul>
+     *
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     SIS.ABOUT.verbose().run();
+     *     }
+     */
+    public static final About ABOUT = new About();
+
+    /**
+     * Builder for the "about" sub-command. This builder provides convenience 
methods
+     * for setting options before to execute the command by a call to {@link 
#run(Object...)}.
+     *
+     * @see #ABOUT
+     */
+    public static final class About extends Builder<About> {
+        /** Creates the unique instance. */
+        About() {super("about");}
+
+        /**
+         * Sets the locale to use for the command output.
+         *
+         * @param  value  the language and country code.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public About locale(String value) {
+            return set(Option.LOCALE, value);
+        }
+
+        /**
+         * Sets the timezone for the dates to be formatted.
+         *
+         * @param  value  the time zone identifier.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public About timezone(String value) {
+            return set(Option.TIMEZONE, value);
+        }
+
+        /**
+         * Sets encoding to use for the command outputs.
+         * This option rarely needs to be specified.
+         *
+         * @param  value  the character set name.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public About encoding(String value) {
+            return set(Option.ENCODING, value);
+        }
+
+        /**
+         * Reduces the output to only brief information.
+         *
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public About brief() {
+            return set(Option.BRIEF, null);
+        }
+
+        /**
+         * Requests the output to contain more detailed information.
+         *
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public About verbose() {
+            return set(Option.VERBOSE, null);
+        }
+    }
+
+
+
+
+    /**
+     * Shows MIME type for the given file.
+     * This sub-command reproduces the functionality of the following Unix 
command,
+     * except that {@code MimeTypeCommand} uses the SIS detection mechanism 
instead of the OS one.
+     *
+     * {@snippet lang="shell" :
+     *   file --mime-type <files>
+     *   }
+     *
+     * Arguments other than options are files, usually as character strings 
but can also be
+     * {@link java.io.File}, {@link java.nio.file.Path} or {@link 
java.net.URL} for example.
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     SIS.MIME_TYPE.run("data.xml");
+     *     }
+     */
+    public static final MimeType MIME_TYPE = new MimeType();
+
+    /**
+     * Builder for the "mime-type" sub-command. This builder provides 
convenience methods
+     * for setting options before to execute the command by a call to {@link 
#run(Object...)}.
+     *
+     * @see #MIME_TYPE
+     */
+    public static final class MimeType extends Builder<MimeType> {
+        /** Creates the unique instance. */
+        MimeType() {super("mime-type");}
+
+        /**
+         * Sets encoding to use for the command outputs.
+         * This option rarely needs to be specified.
+         *
+         * @param  value  the character set name.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public MimeType encoding(String value) {
+            return set(Option.ENCODING, value);
+        }
+    }
+
+    /**
+     * Shows ISO 19115 metadata information for the given file.
+     * Some available options are:
+     *
+     * <ul>
+     *   <li>{@code --format}: the output format (text, XML or GPX).</li>
+     * </ul>
+     *
+     * Arguments other than options are files, usually as character strings 
but can also be
+     * {@link java.io.File}, {@link java.nio.file.Path} or {@link 
java.net.URL} for example.
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     SIS.METADATA.format("xml").run("data.xml");
+     *     }
+     */
+    public static final Metadata METADATA = new Metadata("metadata");
+
+    /**
+     * Shows Coordinate Reference System (CRS) information for the given file.
+     * CRS are considered as a kind of metadata.
+     * Some available options are:
+     *
+     * <ul>
+     *   <li>{@code --format}: the output format (WKT or XML).</li>
+     * </ul>
+     *
+     * Arguments other than options are files, usually as character strings 
but can also be
+     * {@link java.io.File}, {@link java.nio.file.Path} or {@link 
java.net.URL} for example.
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     SIS.CRS.format("wkt").run("data.xml");
+     *     }
+     */
+    public static final Metadata CRS = new Metadata("crs");
+
+    /**
+     * Builder for the "metadata" and "crs" sub-commands. This builder 
provides convenience methods
+     * for setting options before to execute the command by a call to {@link 
#run(Object...)}.
+     *
+     * @see #METADATA
+     * @see #CRS
+     */
+    public static final class Metadata extends Builder<Metadata> {
+        /** Creates the instance for metadata or CRS. */
+        Metadata(String command) {super(command);}
+
+        /**
+         * Sets the output format.
+         *
+         * @param  value  the format. Examples: xml, wkt, wkt1 or text.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Metadata format(String value) {
+            return set(Option.FORMAT, value);
+        }
+
+        /**
+         * Sets the locale to use for the command output.
+         *
+         * @param  value  the language and country code.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Metadata locale(String value) {
+            return set(Option.LOCALE, value);
+        }
+
+        /**
+         * Sets the timezone for the dates to be formatted.
+         *
+         * @param  value  the time zone identifier.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Metadata timezone(String value) {
+            return set(Option.TIMEZONE, value);
+        }
+
+        /**
+         * Sets encoding to use for the command outputs.
+         * This option rarely needs to be specified.
+         *
+         * @param  value  the character set name.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Metadata encoding(String value) {
+            return set(Option.ENCODING, value);
+        }
+
+        /**
+         * Sets whether colorized output shall be enabled.
+         *
+         * @param  enabled  whether colors are enabled.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Metadata colors(boolean enabled) {
+            return set(Option.COLORS, enabled);
+        }
+
+        /**
+         * Requests the output to contain more detailed information.
+         *
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Metadata verbose() {
+            return set(Option.VERBOSE, null);
+        }
+    }
+
+
+
+
+    /**
+     * Shows identifiers for metadata and referencing systems in the given 
file.
+     * Arguments other than options are files, usually as character strings 
but can also be
+     * {@link java.io.File}, {@link java.nio.file.Path} or {@link 
java.net.URL} for example.
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     SIS.IDENTIFIER.run("data.xml");
+     *     }
+     */
+    public static final Identifier IDENTIFIER = new Identifier();
+
+    /**
+     * Builder for the "identifier" sub-command. This builder provides 
convenience methods
+     * for setting options before to execute the command by a call to {@link 
#run(Object...)}.
+     *
+     * @see #IDENTIFIER
+     */
+    public static final class Identifier extends Builder<Identifier> {
+        /** Creates the unique instance. */
+        Identifier() {super("identifier");}
+
+        /**
+         * Sets the locale to use for the command output.
+         *
+         * @param  value  the language and country code.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Identifier locale(String value) {
+            return set(Option.LOCALE, value);
+        }
+
+        /**
+         * Sets encoding to use for the command outputs.
+         * This option rarely needs to be specified.
+         *
+         * @param  value  the character set name.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Identifier encoding(String value) {
+            return set(Option.ENCODING, value);
+        }
+
+        /**
+         * Sets whether colorized output shall be enabled.
+         *
+         * @param  enabled  whether colors are enabled.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Identifier colors(boolean enabled) {
+            return set(Option.COLORS, enabled);
+        }
+
+        /**
+         * Requests the output to contain more detailed information.
+         *
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Identifier verbose() {
+            return set(Option.VERBOSE, null);
+        }
+    }
+
+
+
+
+    /**
+     * Converts or transform coordinates from given source CRS to target CRS.
+     * The output uses comma separated values (CSV) format,
+     * with {@code '#'} as the first character of comment lines.
+     * The source and target CRS are mandatory and can be specified
+     * as EPSG codes, WKT strings, or metadata read from data files.
+     * Those information are passed as options:
+     *
+     * <ul>
+     *   <li>{@code --sourceCRS}: the coordinate reference system of input 
points.</li>
+     *   <li>{@code --targetCRS}: the coordinate reference system of output 
points.</li>
+     * </ul>
+     *
+     * Arguments other than options are files, usually as character strings 
but can also be
+     * {@link java.io.File}, {@link java.nio.file.Path} or {@link 
java.net.URL} for example.
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     
SIS.TRANSFORM.sourceCRS("EPSG:3395").targetCRS("EPSG:4326").run("data.txt");
+     *     }
+     */
+    public static final Transform TRANSFORM = new Transform();
+
+    /**
+     * Builder for the "transform" sub-command. This builder provides 
convenience methods
+     * for setting options before to execute the command by a call to {@link 
#run(Object...)}.
+     *
+     * @see #TRANSFORM
+     */
+    public static final class Transform extends Builder<Transform> {
+        /** Creates the unique instance. */
+        Transform() {super("transform");}
+
+        /**
+         * Sets Coordinate Reference System of input data.
+         *
+         * @param  value  the EPSG code, WKT or file from which to get the CRS.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Transform sourceCRS(Object value) {
+            return set(Option.SOURCE_CRS, value);
+        }
+
+        /**
+         * Sets Coordinate Reference System of output data.
+         *
+         * @param  value  the EPSG code, WKT or file from which to get the CRS.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Transform targetCRS(Object value) {
+            return set(Option.TARGET_CRS, value);
+        }
+
+        /**
+         * Sets the locale to use for the command output.
+         *
+         * @param  value  the language and country code.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Transform locale(String value) {
+            return set(Option.LOCALE, value);
+        }
+
+        /**
+         * Sets the timezone for the dates to be formatted.
+         *
+         * @param  value  the time zone identifier.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Transform timezone(String value) {
+            return set(Option.TIMEZONE, value);
+        }
+
+        /**
+         * Sets encoding to use for the command outputs.
+         * This option rarely needs to be specified.
+         *
+         * @param  value  the character set name.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Transform encoding(String value) {
+            return set(Option.ENCODING, value);
+        }
+
+        /**
+         * Sets whether colorized output shall be enabled.
+         *
+         * @param  enabled  whether colors are enabled.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Transform colors(boolean enabled) {
+            return set(Option.COLORS, enabled);
+        }
+
+        /**
+         * Requests the output to contain more detailed information.
+         *
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Transform verbose() {
+            return set(Option.VERBOSE, null);
+        }
+    }
+
+
+
+
+    /**
+     * Rewrites a data file in another format.
+     * If more than one source file is specified, then all those files are 
aggregated in the output file.
+     * This is possible only if the output format supports the storage of an 
arbitrary number of resources.
+     * Some options are:
+     *
+     * <ul>
+     *   <li>{@code --output}: the file where to write the image.</li>
+     * </ul>
+     *
+     * Arguments are usually character strings but can also be
+     * {@link java.io.File}, {@link java.nio.file.Path} or {@link 
java.net.URL} for example.
+     * Usage example:
+     *
+     * {@snippet lang="java" :
+     *     SIS.TRANSLATE.output("data.tiff").run("data.png");
+     *     }
+     */
+    public static final Translate TRANSLATE = new Translate();
+
+    /**
+     * Builder for the "translate" sub-command. This builder provides 
convenience methods
+     * for setting options before to execute the command by a call to {@link 
#run(Object...)}.
+     *
+     * @see #TRANSLATE
+     */
+    public static final class Translate extends Builder<Translate> {
+        /** Creates the unique instance. */
+        Translate() {super("translate");}
+
+        /**
+         * Sets the destination file.
+         *
+         * @param  value  the output file.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Translate output(Object value) {
+            return set(Option.OUTPUT, value);
+        }
+
+        /**
+         * Sets the output format.
+         *
+         * @param  value  the format. Examples: xml, wkt, wkt1 or text.
+         * @return a new builder or {@code this}, for method call chaining.
+         */
+        public Translate format(String value) {
+            return set(Option.FORMAT, value);
+        }
+    }
+
+
+
+
+    /**
+     * The object to use for formatting WKT objects, created when first needed.
+     */
+    private static WKTFormat wktFormat;
+
+    /**
+     * Prints the given object to the standard output stream.
+     *
+     * @param  value  the object to print.
+     */
+    @SuppressWarnings("UseOfSystemOutOrSystemErr")
+    public static void print(final Object value) {
+        final PrintWriter out = CommandRunner.writer(System.console(), 
System.out);
+        if (value instanceof FormattableObject) {
+            synchronized (SIS.class) {
+                if (wktFormat == null) {
+                    wktFormat = new WKTFormat(null, null);
+                    if (X364.isAnsiSupported()) {
+                        wktFormat.setColors(Colors.DEFAULT);
+                    }
+                }
+                out.print(wktFormat.format(value));
+            }
+        } else {
+            out.println(value);
+        }
+        out.flush();
+    }
+}
diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sis_shell 
b/optional/src/org.apache.sis.gui/bundle/bin/sis_shell
new file mode 100755
index 0000000000..4559adf68f
--- /dev/null
+++ b/optional/src/org.apache.sis.gui/bundle/bin/sis_shell
@@ -0,0 +1,29 @@
+#!/bin/sh
+# ------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ------------------------------------------------------------------------
+
+set -o errexit
+
+SIS_HOME="`dirname "$( readlink -e "$0"; )";`/.."
+SIS_DATA="${SIS_DATA:-$SIS_HOME/data}"
+export SIS_DATA
+export SIS_HOME
+
+jshell --module-path 
"$SIS_HOME/lib:$SIS_HOME/lib/app/org.apache.sis.console.jar" \
+       --add-module org.apache.sis.console \
+       --startup "$SIS_HOME/conf/imports.jsh" \
+       "$@"
diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sis_shell.bat 
b/optional/src/org.apache.sis.gui/bundle/bin/sis_shell.bat
new file mode 100644
index 0000000000..5e526285c4
--- /dev/null
+++ b/optional/src/org.apache.sis.gui/bundle/bin/sis_shell.bat
@@ -0,0 +1,25 @@
+@echo off
+
+REM Licensed to the Apache Software Foundation (ASF) under one or more
+REM contributor license agreements.  See the NOTICE file distributed with
+REM this work for additional information regarding copyright ownership.
+REM The ASF licenses this file to you under the Apache License, Version 2.0
+REM (the "License"); you may not use this file except in compliance with the
+REM License.  You may obtain a copy of the License at
+REM
+REM    http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing, software
+REM distributed under the License is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM See the License for the specific language governing permissions and
+REM limitations under the License.
+
+
+SET SIS_HOME=%~dp0\..
+SET SIS_DATA=%SIS_HOME%\data
+
+jshell --module-path 
"%SIS_HOME%\lib;%SIS_HOME%\lib\app\org.apache.sis.console.jar"^
+       --add-module org.apache.sis.console^
+       --startup "%SIS_HOME%\conf\imports.jsh"^
+       %*
diff --git a/optional/src/org.apache.sis.gui/bundle/conf/imports.jsh 
b/optional/src/org.apache.sis.gui/bundle/conf/imports.jsh
new file mode 100644
index 0000000000..ddf130cb4b
--- /dev/null
+++ b/optional/src/org.apache.sis.gui/bundle/conf/imports.jsh
@@ -0,0 +1,299 @@
+// Only math functions working on floating point numbers.
+import static java.lang.Math.E;
+import static java.lang.Math.PI;
+import static java.lang.Math.abs;
+import static java.lang.Math.acos;
+import static java.lang.Math.asin;
+import static java.lang.Math.atan;
+import static java.lang.Math.atan2;
+import static java.lang.Math.cbrt;
+import static java.lang.Math.ceil;
+import static java.lang.Math.copySign;
+import static java.lang.Math.cos;
+import static java.lang.Math.cosh;
+import static java.lang.Math.exp;
+import static java.lang.Math.expm1;
+import static java.lang.Math.floor;
+import static java.lang.Math.fma;
+import static java.lang.Math.hypot;
+import static java.lang.Math.log;
+import static java.lang.Math.log10;
+import static java.lang.Math.log1p;
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+import static java.lang.Math.nextAfter;
+import static java.lang.Math.nextDown;
+import static java.lang.Math.nextUp;
+import static java.lang.Math.rint;
+import static java.lang.Math.round;
+import static java.lang.Math.scalb;
+import static java.lang.Math.signum;
+import static java.lang.Math.sin;
+import static java.lang.Math.sinh;
+import static java.lang.Math.sqrt;
+import static java.lang.Math.tan;
+import static java.lang.Math.tanh;
+import static java.lang.Math.toDegrees;
+import static java.lang.Math.toRadians;
+import static java.lang.Math.ulp;
+
+// Arbitrary precision arithmetic.
+import java.math.*;
+
+// Main I/O objects.
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.Flushable;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.file.AccessMode;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitor;
+import java.nio.file.FileVisitResult;
+import java.nio.file.InvalidPathException;
+import java.nio.file.LinkOption;
+import java.nio.file.LinkPermission;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.net.URL;
+import java.net.URI;
+
+// Most interesting utilities, excluding calendar.
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Currency;
+import java.util.Date;
+import java.util.Deque;
+import java.util.DoubleSummaryStatistics;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.IntSummaryStatistics;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Locale;
+import java.util.LongSummaryStatistics;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.PriorityQueue;
+import java.util.Properties;
+import java.util.Queue;
+import java.util.Random;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.StringJoiner;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.WeakHashMap;
+import java.util.regex.*;
+import java.util.stream.*;
+import java.util.function.*;
+
+// Time objects preferred to calendar.
+import java.time.DayOfWeek;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+
+// Unit of measurement.
+import javax.measure.Quantity;
+import javax.measure.Unit;
+import javax.measure.UnitConverter;
+
+// GeoAPI main objects.
+import org.opengis.util.CodeList
+import org.opengis.util.FactoryException
+import org.opengis.util.GenericName
+import org.opengis.util.InternationalString
+import org.opengis.metadata.Identifier;
+import org.opengis.metadata.Metadata;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.opengis.metadata.extent.GeographicDescription;
+import org.opengis.metadata.extent.GeographicExtent;
+import org.opengis.metadata.extent.SpatialTemporalExtent;
+import org.opengis.metadata.extent.TemporalExtent;
+import org.opengis.metadata.extent.VerticalExtent;
+import org.opengis.metadata.identification.DataIdentification;
+import org.opengis.metadata.identification.Identification;
+import org.opengis.metadata.quality.DataQuality;
+import org.opengis.metadata.quality.PositionalAccuracy;
+import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.geometry.Envelope;
+import org.opengis.referencing.crs.CompoundCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.DerivedCRS;
+import org.opengis.referencing.crs.GeodeticCRS;
+import org.opengis.referencing.crs.EngineeringCRS;
+import org.opengis.referencing.crs.GeneralDerivedCRS;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.crs.SingleCRS;
+import org.opengis.referencing.crs.TemporalCRS;
+import org.opengis.referencing.crs.VerticalCRS;
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.cs.RangeMeaning;
+import org.opengis.referencing.datum.Datum;
+import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.datum.PixelInCell;
+import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.operation.ConcatenatedOperation;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform1D;
+import org.opengis.referencing.operation.MathTransform2D;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
+import org.opengis.referencing.operation.TransformException;
+
+// Apache SIS.
+import org.apache.sis.math.Fraction;
+import org.apache.sis.measure.Angle;
+import org.apache.sis.measure.Latitude;
+import org.apache.sis.measure.Longitude;
+import org.apache.sis.measure.MeasurementRange;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.measure.Quantities;
+import org.apache.sis.measure.Range;
+import org.apache.sis.measure.Units;
+import org.apache.sis.util.collection.TableColumn;
+import org.apache.sis.util.collection.TreeTable;
+import org.apache.sis.util.iso.Names;
+import org.apache.sis.xml.NilObject;
+import org.apache.sis.xml.NilReason;
+import org.apache.sis.xml.XML;
+import org.apache.sis.geometry.GeneralDirectPosition;
+import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.geometry.Envelopes;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.GeodeticCalculator;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.crs.AbstractCRS;
+import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.feature.builder.AssociationRoleBuilder;
+import org.apache.sis.feature.builder.AttributeRole;
+import org.apache.sis.feature.builder.AttributeTypeBuilder;
+import org.apache.sis.feature.builder.CharacteristicTypeBuilder;
+import org.apache.sis.feature.builder.FeatureTypeBuilder;
+import org.apache.sis.feature.builder.PropertyTypeBuilder;
+import org.apache.sis.feature.builder.TypeBuilder;
+import org.apache.sis.filter.DefaultFilterFactory;
+import org.apache.sis.coverage.BandedCoverage;
+import org.apache.sis.coverage.Category;
+import org.apache.sis.coverage.CoverageCombiner;
+import org.apache.sis.coverage.RegionOfInterest;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.GridClippingMode;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridCoverage2D;
+import org.apache.sis.coverage.grid.GridCoverageBuilder;
+import org.apache.sis.coverage.grid.GridCoverageProcessor;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.coverage.grid.GridOrientation;
+import org.apache.sis.coverage.grid.GridRoundingMode;
+import org.apache.sis.storage.Aggregate;
+import org.apache.sis.storage.CoverageQuery;
+import org.apache.sis.storage.DataSet;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStores;
+import org.apache.sis.storage.FeatureQuery;
+import org.apache.sis.storage.FeatureSet;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.Query;
+import org.apache.sis.storage.RasterLoadingStrategy;
+import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.WritableAggregate;
+import org.apache.sis.storage.WritableFeatureSet;
+import org.apache.sis.storage.WritableGridCoverageResource;
+import org.apache.sis.console.SIS;
+import static org.apache.sis.console.SIS.print;
+
+// Initialization
+org.apache.sis.console.Command.configureLogging()


Reply via email to