diff --git a/.github/build.sh b/.github/build.sh index 7da42622b..523abeb87 100755 --- a/.github/build.sh +++ b/.github/build.sh @@ -1,3 +1,3 @@ #!/bin/sh -curl -fsLO https://raw.githubusercontent.com/scijava/scijava-scripts/master/ci-build.sh +curl -fsLO https://raw.githubusercontent.com/scijava/scijava-scripts/main/ci-build.sh sh ci-build.sh diff --git a/.github/setup.sh b/.github/setup.sh index f359bbeeb..0ebca586f 100755 --- a/.github/setup.sh +++ b/.github/setup.sh @@ -1,3 +1,10 @@ #!/bin/sh -curl -fsLO https://raw.githubusercontent.com/scijava/scijava-scripts/master/ci-setup-github-actions.sh +curl -fsLO https://raw.githubusercontent.com/scijava/scijava-scripts/main/ci-setup-github-actions.sh sh ci-setup-github-actions.sh + +# Let the Linux build handle artifact deployment. +if [ "$(uname)" != Linux ] +then + echo "No deploy -- non-Linux build" + echo "NO_DEPLOY=1" >> $GITHUB_ENV +fi diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml deleted file mode 100644 index 925b57658..000000000 --- a/.github/workflows/build-pr.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: build PR - -on: - pull_request: - branches: - - master - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Java - uses: actions/setup-java@v3 - with: - java-version: '8' - distribution: 'zulu' - cache: 'maven' - - name: Set up CI environment - run: .github/setup.sh - - name: Execute the build - run: .github/build.sh diff --git a/.github/workflows/build-main.yml b/.github/workflows/build.yml similarity index 60% rename from .github/workflows/build-main.yml rename to .github/workflows/build.yml index 5ef569202..a57c0df0b 100644 --- a/.github/workflows/build-main.yml +++ b/.github/workflows/build.yml @@ -6,27 +6,37 @@ on: - master tags: - "*-[0-9]+.*" + pull_request: + branches: + - master jobs: build: - runs-on: ubuntu-latest + name: build-${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '8' distribution: 'zulu' cache: 'maven' - name: Set up CI environment run: .github/setup.sh + shell: bash - name: Execute the build run: .github/build.sh + shell: bash env: GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} MAVEN_USER: ${{ secrets.MAVEN_USER }} MAVEN_PASS: ${{ secrets.MAVEN_PASS }} - OSSRH_PASS: ${{ secrets.OSSRH_PASS }} + CENTRAL_USER: ${{ secrets.CENTRAL_USER }} + CENTRAL_PASS: ${{ secrets.CENTRAL_PASS }} SIGNING_ASC: ${{ secrets.SIGNING_ASC }} diff --git a/LICENSE.txt b/LICENSE.txt index 5f08911f4..55024a7c5 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2009 - 2022, SciJava developers. +Copyright (c) 2009 - 2026, SciJava developers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/NOTICE.txt b/NOTICE.txt index 74385d300..5b605b01d 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,11 +1,12 @@ This project contains code adapted from Apache Commons Lang (https://commons.apache.org/proper/commons-lang/) version 3.4, as well as GenTyRef (https://github.com/coekie/gentyref) version 1.1.0, -both of which are licensed under the Apache 2.0 license, as follows: +and EventBus (https://github.com/michaelbushe/EventBus) version 1.4, +each of which is licensed under the Apache 2.0 license, as follows: Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -197,7 +198,7 @@ both of which are licensed under the Apache 2.0 license, as follows: 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 + https://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, diff --git a/README.md b/README.md index 06c483c15..ba1f15173 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![](https://img.shields.io/maven-central/v/org.scijava/scijava-common.svg)](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.scijava%22%20AND%20a%3A%22scijava-common%22) -[![](https://github.com/scijava/scijava-common/actions/workflows/build-main.yml/badge.svg)](https://github.com/scijava/scijava-common/actions/workflows/build-main.yml) -[![Join the chat at https://gitter.im/scijava/scijava-common](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/scijava/scijava-common?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![](https://img.shields.io/maven-central/v/org.scijava/scijava-common.svg)](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.scijava%22%20AND%20a%3A%22scijava-common%22) +[![](https://github.com/scijava/scijava-common/actions/workflows/build.yml/badge.svg)](https://github.com/scijava/scijava-common/actions/workflows/build.yml) +[![developer chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://imagesc.zulipchat.com/#narrow/stream/327237-SciJava) SciJava Common is a common library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed diff --git a/pom.xml b/pom.xml index fca6aef22..30c6d9a53 100644 --- a/pom.xml +++ b/pom.xml @@ -5,12 +5,12 @@ org.scijava pom-scijava - 32.0.0-beta-3 + 43.0.0 scijava-common - 2.88.3-SNAPSHOT + 2.100.1-SNAPSHOT SciJava Common 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 downstream projects in the SciJava ecosystem, such as ImageJ and SCIFIO. @@ -134,6 +134,11 @@ https://imagej.net/people/jaywarrick jaywarrick + + Christian Tischer + https://imagej.net/people/tischi + tischi + @@ -167,6 +172,10 @@ bsd_2 SciJava Common shared library for SciJava software. SciJava developers. + **/bushe/** + + + 2.22.2 @@ -176,13 +185,6 @@ parsington - - - org.bushe - eventbus - 1.4 - - junit @@ -193,7 +195,7 @@ org.mockito mockito-core test - + diff --git a/src/it/apt-test/pom.xml b/src/it/apt-test/pom.xml index 8bfa04980..c416a3860 100644 --- a/src/it/apt-test/pom.xml +++ b/src/it/apt-test/pom.xml @@ -3,7 +3,7 @@ #%L SciJava Common shared library for SciJava software. %% - Copyright (C) 2009 - 2022 SciJava developers. + Copyright (C) 2009 - 2026 SciJava developers. %% Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -31,7 +31,7 @@ + https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 @project.groupId@ diff --git a/src/it/apt-test/setup.bsh b/src/it/apt-test/setup.bsh index 1aa0b6938..30380371c 100644 --- a/src/it/apt-test/setup.bsh +++ b/src/it/apt-test/setup.bsh @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/it/apt-test/src/main/java/org/scijava/annotation/its/Annotated.java b/src/it/apt-test/src/main/java/org/scijava/annotation/its/Annotated.java index 1bda32ca5..2d9e5d420 100644 --- a/src/it/apt-test/src/main/java/org/scijava/annotation/its/Annotated.java +++ b/src/it/apt-test/src/main/java/org/scijava/annotation/its/Annotated.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/it/apt-test/src/main/java/org/scijava/annotation/its/CustomAnnotation.java b/src/it/apt-test/src/main/java/org/scijava/annotation/its/CustomAnnotation.java index 77e414da2..1b456f1c3 100644 --- a/src/it/apt-test/src/main/java/org/scijava/annotation/its/CustomAnnotation.java +++ b/src/it/apt-test/src/main/java/org/scijava/annotation/its/CustomAnnotation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/it/apt-test/verify.bsh b/src/it/apt-test/verify.bsh index bf20d6cc0..679bbf6ed 100644 --- a/src/it/apt-test/verify.bsh +++ b/src/it/apt-test/verify.bsh @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/it/settings.xml b/src/it/settings.xml index be7d7b999..b3042e9e1 100644 --- a/src/it/settings.xml +++ b/src/it/settings.xml @@ -3,7 +3,7 @@ #%L SciJava Common shared library for SciJava software. %% - Copyright (C) 2009 - 2022 SciJava developers. + Copyright (C) 2009 - 2026 SciJava developers. %% Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/AbstractBasicDetails.java b/src/main/java/org/scijava/AbstractBasicDetails.java index 96ba66746..75e28c611 100644 --- a/src/main/java/org/scijava/AbstractBasicDetails.java +++ b/src/main/java/org/scijava/AbstractBasicDetails.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/AbstractContextual.java b/src/main/java/org/scijava/AbstractContextual.java index b8a074336..6d47180bf 100644 --- a/src/main/java/org/scijava/AbstractContextual.java +++ b/src/main/java/org/scijava/AbstractContextual.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/AbstractGateway.java b/src/main/java/org/scijava/AbstractGateway.java index c6be31959..14f066a7f 100644 --- a/src/main/java/org/scijava/AbstractGateway.java +++ b/src/main/java/org/scijava/AbstractGateway.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,6 +42,7 @@ import org.scijava.input.InputService; import org.scijava.io.IOService; import org.scijava.io.RecentFileService; +import org.scijava.io.location.LocationService; import org.scijava.log.LogService; import org.scijava.main.MainService; import org.scijava.menu.MenuService; @@ -190,6 +191,11 @@ public InputService input() { public IOService io() { return get(IOService.class); } + + @Override + public LocationService location() { + return get(LocationService.class); + } @Override public LogService log() { diff --git a/src/main/java/org/scijava/AbstractUIDetails.java b/src/main/java/org/scijava/AbstractUIDetails.java index 0b887cafa..11476a03a 100644 --- a/src/main/java/org/scijava/AbstractUIDetails.java +++ b/src/main/java/org/scijava/AbstractUIDetails.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/BasicDetails.java b/src/main/java/org/scijava/BasicDetails.java index b3ab1e40f..6c37807e6 100644 --- a/src/main/java/org/scijava/BasicDetails.java +++ b/src/main/java/org/scijava/BasicDetails.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Cancelable.java b/src/main/java/org/scijava/Cancelable.java index 0b1098ca0..5bc0fe61c 100644 --- a/src/main/java/org/scijava/Cancelable.java +++ b/src/main/java/org/scijava/Cancelable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Context.java b/src/main/java/org/scijava/Context.java index f93f22991..bfb118099 100644 --- a/src/main/java/org/scijava/Context.java +++ b/src/main/java/org/scijava/Context.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,11 +33,15 @@ import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.scijava.event.ContextCreatedEvent; import org.scijava.event.ContextDisposingEvent; import org.scijava.event.EventHandler; import org.scijava.event.EventService; @@ -72,6 +76,14 @@ public class Context implements Disposable, AutoCloseable { */ public static final String STRICT_PROPERTY = "scijava.context.strict"; + /** Set of currently active (not disposed) application contexts. */ + private static final Map CONTEXTS = + new ConcurrentHashMap<>(); // NB: ConcurrentHashMap disallows nulls. + + // -- Static fields -- + + private static Thread shutdownThread = null; + // -- Fields -- /** Index of the application context's services. */ @@ -97,6 +109,12 @@ public class Context implements Disposable, AutoCloseable { */ private boolean strict; + /** + * False if the context is currently active; true if the context + * has already been disposed, or is in the process of being disposed. + */ + private boolean disposed; + /** * Creates a new SciJava application context with all available services. * @@ -284,6 +302,26 @@ public Context(final Collection> serviceClasses, new ServiceHelper(this, serviceClasses, strict); serviceHelper.loadServices(); } + + // If JVM shuts down with context still active, clean up after ourselves. + if (shutdownThread == null) { + synchronized (Context.class) { + if (shutdownThread == null) { + shutdownThread = new Thread(() -> { + final List contexts = new ArrayList<>(CONTEXTS.keySet()); + for (final Context context : contexts) { + context.doDispose(false); + } + }); + Runtime.getRuntime().addShutdownHook(shutdownThread); + } + } + } + CONTEXTS.put(this, true); + + // Publish an event to indicate that context initialization is complete. + final EventService eventService = getService(EventService.class); + if (eventService != null) eventService.publish(new ContextCreatedEvent()); } // -- Context methods -- @@ -418,16 +456,7 @@ public boolean isInjectable(final Class type) { @Override public void dispose() { - final EventService eventService = getService(EventService.class); - if (eventService != null) eventService.publish(new ContextDisposingEvent()); - - // NB: Dispose services in reverse order. - // This may or may not actually be necessary, but seems safer, since - // dependent services will be disposed *before* their dependencies. - final List services = serviceIndex.getAll(); - for (int s = services.size() - 1; s >= 0; s--) { - services.get(s).dispose(); - } + doDispose(true); } // -- AutoCloseable methods -- @@ -580,6 +609,24 @@ private String createMissingServiceMessage( return msg.toString(); } + private synchronized void doDispose(final boolean announce) { + if (disposed) return; + disposed = true; + CONTEXTS.remove(this); + if (announce) { + final EventService eventService = getService(EventService.class); + if (eventService != null) eventService.publish(new ContextDisposingEvent()); + } + + // NB: Dispose services in reverse order. + // This may or may not actually be necessary, but seems safer, since + // dependent services will be disposed *before* their dependencies. + final List services = serviceIndex.getAll(); + for (int s = services.size() - 1; s >= 0; s--) { + services.get(s).dispose(); + } + } + private static PluginIndex plugins(final boolean empty) { return empty ? new PluginIndex(null) : null; } diff --git a/src/main/java/org/scijava/Contextual.java b/src/main/java/org/scijava/Contextual.java index cd247a466..f76c7fc0d 100644 --- a/src/main/java/org/scijava/Contextual.java +++ b/src/main/java/org/scijava/Contextual.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Disposable.java b/src/main/java/org/scijava/Disposable.java index cde51c0fc..ac72c90b4 100644 --- a/src/main/java/org/scijava/Disposable.java +++ b/src/main/java/org/scijava/Disposable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Gateway.java b/src/main/java/org/scijava/Gateway.java index 47b346156..7cd98413e 100644 --- a/src/main/java/org/scijava/Gateway.java +++ b/src/main/java/org/scijava/Gateway.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,6 +40,7 @@ import org.scijava.input.InputService; import org.scijava.io.IOService; import org.scijava.io.RecentFileService; +import org.scijava.io.location.LocationService; import org.scijava.log.LogService; import org.scijava.main.MainService; import org.scijava.menu.MenuService; @@ -238,6 +239,13 @@ public interface Gateway extends RichPlugin, Disposable { */ IOService io(); + /** + * Gets this application context's {@link LocationService}. + * + * @return The {@link LocationService} of this application context. + */ + LocationService location(); + /** * Gets this application context's {@link LogService}. * diff --git a/src/main/java/org/scijava/Identifiable.java b/src/main/java/org/scijava/Identifiable.java index 0774e0fb2..53db16039 100644 --- a/src/main/java/org/scijava/Identifiable.java +++ b/src/main/java/org/scijava/Identifiable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Initializable.java b/src/main/java/org/scijava/Initializable.java index 149e8d503..56aa725ae 100644 --- a/src/main/java/org/scijava/Initializable.java +++ b/src/main/java/org/scijava/Initializable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Instantiable.java b/src/main/java/org/scijava/Instantiable.java index 5be5d288d..3edca09a4 100644 --- a/src/main/java/org/scijava/Instantiable.java +++ b/src/main/java/org/scijava/Instantiable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/InstantiableException.java b/src/main/java/org/scijava/InstantiableException.java index bf31a522f..0ad031f7b 100644 --- a/src/main/java/org/scijava/InstantiableException.java +++ b/src/main/java/org/scijava/InstantiableException.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ItemIO.java b/src/main/java/org/scijava/ItemIO.java index e9955fcaf..fa8b68684 100644 --- a/src/main/java/org/scijava/ItemIO.java +++ b/src/main/java/org/scijava/ItemIO.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ItemVisibility.java b/src/main/java/org/scijava/ItemVisibility.java index d69da15d2..47897a359 100644 --- a/src/main/java/org/scijava/ItemVisibility.java +++ b/src/main/java/org/scijava/ItemVisibility.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Locatable.java b/src/main/java/org/scijava/Locatable.java index e200df42e..a7da30625 100644 --- a/src/main/java/org/scijava/Locatable.java +++ b/src/main/java/org/scijava/Locatable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/MenuEntry.java b/src/main/java/org/scijava/MenuEntry.java index ee0ac4b75..4a2b33bb9 100644 --- a/src/main/java/org/scijava/MenuEntry.java +++ b/src/main/java/org/scijava/MenuEntry.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/MenuPath.java b/src/main/java/org/scijava/MenuPath.java index 508eec37b..533fd2461 100644 --- a/src/main/java/org/scijava/MenuPath.java +++ b/src/main/java/org/scijava/MenuPath.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Named.java b/src/main/java/org/scijava/Named.java index 2307e06f3..9a381ee3a 100644 --- a/src/main/java/org/scijava/Named.java +++ b/src/main/java/org/scijava/Named.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/NoSuchServiceException.java b/src/main/java/org/scijava/NoSuchServiceException.java index 498c0989f..d97d95647 100644 --- a/src/main/java/org/scijava/NoSuchServiceException.java +++ b/src/main/java/org/scijava/NoSuchServiceException.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/NullContextException.java b/src/main/java/org/scijava/NullContextException.java index 7c13e82ba..794926da9 100644 --- a/src/main/java/org/scijava/NullContextException.java +++ b/src/main/java/org/scijava/NullContextException.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Optional.java b/src/main/java/org/scijava/Optional.java index 8ce2fc46f..2ab55b3c9 100644 --- a/src/main/java/org/scijava/Optional.java +++ b/src/main/java/org/scijava/Optional.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Prioritized.java b/src/main/java/org/scijava/Prioritized.java index bb49dc76f..86bd0691a 100644 --- a/src/main/java/org/scijava/Prioritized.java +++ b/src/main/java/org/scijava/Prioritized.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Priority.java b/src/main/java/org/scijava/Priority.java index a495ec026..69da7767e 100644 --- a/src/main/java/org/scijava/Priority.java +++ b/src/main/java/org/scijava/Priority.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/SciJava.java b/src/main/java/org/scijava/SciJava.java index 3c1180e43..81375dcd6 100644 --- a/src/main/java/org/scijava/SciJava.java +++ b/src/main/java/org/scijava/SciJava.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Typed.java b/src/main/java/org/scijava/Typed.java index a600d4718..cfb55d690 100644 --- a/src/main/java/org/scijava/Typed.java +++ b/src/main/java/org/scijava/Typed.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/UIDetails.java b/src/main/java/org/scijava/UIDetails.java index 949cf24cb..ccf12c261 100644 --- a/src/main/java/org/scijava/UIDetails.java +++ b/src/main/java/org/scijava/UIDetails.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Validated.java b/src/main/java/org/scijava/Validated.java index f3383a252..11835ba5c 100644 --- a/src/main/java/org/scijava/Validated.java +++ b/src/main/java/org/scijava/Validated.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ValidityProblem.java b/src/main/java/org/scijava/ValidityProblem.java index 65cfa240c..782bcc642 100644 --- a/src/main/java/org/scijava/ValidityProblem.java +++ b/src/main/java/org/scijava/ValidityProblem.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/Versioned.java b/src/main/java/org/scijava/Versioned.java index c12d5be9b..6e746dad4 100644 --- a/src/main/java/org/scijava/Versioned.java +++ b/src/main/java/org/scijava/Versioned.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/AbstractIndexWriter.java b/src/main/java/org/scijava/annotations/AbstractIndexWriter.java index 9132512e6..28fe310a5 100644 --- a/src/main/java/org/scijava/annotations/AbstractIndexWriter.java +++ b/src/main/java/org/scijava/annotations/AbstractIndexWriter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/AnnotationCombiner.java b/src/main/java/org/scijava/annotations/AnnotationCombiner.java index 88f92ca9e..9b152b924 100644 --- a/src/main/java/org/scijava/annotations/AnnotationCombiner.java +++ b/src/main/java/org/scijava/annotations/AnnotationCombiner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/AnnotationProcessor.java b/src/main/java/org/scijava/annotations/AnnotationProcessor.java index 03cc759b0..8355dcda9 100644 --- a/src/main/java/org/scijava/annotations/AnnotationProcessor.java +++ b/src/main/java/org/scijava/annotations/AnnotationProcessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/ByteCodeAnalyzer.java b/src/main/java/org/scijava/annotations/ByteCodeAnalyzer.java index 316ce2601..915d9148f 100644 --- a/src/main/java/org/scijava/annotations/ByteCodeAnalyzer.java +++ b/src/main/java/org/scijava/annotations/ByteCodeAnalyzer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/DirectoryIndexer.java b/src/main/java/org/scijava/annotations/DirectoryIndexer.java index 84a176e00..ac6be8fcd 100644 --- a/src/main/java/org/scijava/annotations/DirectoryIndexer.java +++ b/src/main/java/org/scijava/annotations/DirectoryIndexer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/EclipseHelper.java b/src/main/java/org/scijava/annotations/EclipseHelper.java index d8b457f29..67f17ff7d 100644 --- a/src/main/java/org/scijava/annotations/EclipseHelper.java +++ b/src/main/java/org/scijava/annotations/EclipseHelper.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/Index.java b/src/main/java/org/scijava/annotations/Index.java index e9fe9a5c4..244b00d37 100644 --- a/src/main/java/org/scijava/annotations/Index.java +++ b/src/main/java/org/scijava/annotations/Index.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/IndexItem.java b/src/main/java/org/scijava/annotations/IndexItem.java index 3a3fc8b54..e5265fc21 100644 --- a/src/main/java/org/scijava/annotations/IndexItem.java +++ b/src/main/java/org/scijava/annotations/IndexItem.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/IndexReader.java b/src/main/java/org/scijava/annotations/IndexReader.java index 061226272..4eab67552 100644 --- a/src/main/java/org/scijava/annotations/IndexReader.java +++ b/src/main/java/org/scijava/annotations/IndexReader.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/Indexable.java b/src/main/java/org/scijava/annotations/Indexable.java index 31315dcf0..325739efd 100644 --- a/src/main/java/org/scijava/annotations/Indexable.java +++ b/src/main/java/org/scijava/annotations/Indexable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/annotations/legacy/LegacyReader.java b/src/main/java/org/scijava/annotations/legacy/LegacyReader.java index 300a03da0..9df62abcc 100644 --- a/src/main/java/org/scijava/annotations/legacy/LegacyReader.java +++ b/src/main/java/org/scijava/annotations/legacy/LegacyReader.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/app/AbstractApp.java b/src/main/java/org/scijava/app/AbstractApp.java index 3efbfc005..33ff29ff4 100644 --- a/src/main/java/org/scijava/app/AbstractApp.java +++ b/src/main/java/org/scijava/app/AbstractApp.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/app/App.java b/src/main/java/org/scijava/app/App.java index ad603f17f..95cf249e7 100644 --- a/src/main/java/org/scijava/app/App.java +++ b/src/main/java/org/scijava/app/App.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -144,7 +144,7 @@ default void quit() { /** * Gets the version of the application. *

- * SciJava conforms to the Semantic + * SciJava conforms to the Semantic * Versioning specification. *

* diff --git a/src/main/java/org/scijava/app/AppService.java b/src/main/java/org/scijava/app/AppService.java index 876475de3..2d9c7e3de 100644 --- a/src/main/java/org/scijava/app/AppService.java +++ b/src/main/java/org/scijava/app/AppService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/app/DefaultAppService.java b/src/main/java/org/scijava/app/DefaultAppService.java index 26642e99b..9c8afc0c3 100644 --- a/src/main/java/org/scijava/app/DefaultAppService.java +++ b/src/main/java/org/scijava/app/DefaultAppService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/app/DefaultStatusService.java b/src/main/java/org/scijava/app/DefaultStatusService.java index c622c12ea..1b68a27ba 100644 --- a/src/main/java/org/scijava/app/DefaultStatusService.java +++ b/src/main/java/org/scijava/app/DefaultStatusService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/app/SciJavaApp.java b/src/main/java/org/scijava/app/SciJavaApp.java index 1c9679b06..b7604ca14 100644 --- a/src/main/java/org/scijava/app/SciJavaApp.java +++ b/src/main/java/org/scijava/app/SciJavaApp.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/app/StatusService.java b/src/main/java/org/scijava/app/StatusService.java index e2c64ebf0..70d0edf75 100644 --- a/src/main/java/org/scijava/app/StatusService.java +++ b/src/main/java/org/scijava/app/StatusService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/app/event/StatusEvent.java b/src/main/java/org/scijava/app/event/StatusEvent.java index cb34e3f4e..653aefb8e 100644 --- a/src/main/java/org/scijava/app/event/StatusEvent.java +++ b/src/main/java/org/scijava/app/event/StatusEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/cache/CacheService.java b/src/main/java/org/scijava/cache/CacheService.java index f91b37214..ca5808918 100644 --- a/src/main/java/org/scijava/cache/CacheService.java +++ b/src/main/java/org/scijava/cache/CacheService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/cache/DefaultCacheService.java b/src/main/java/org/scijava/cache/DefaultCacheService.java index 210ed2558..667ffdb30 100644 --- a/src/main/java/org/scijava/cache/DefaultCacheService.java +++ b/src/main/java/org/scijava/cache/DefaultCacheService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/Command.java b/src/main/java/org/scijava/command/Command.java index 420c5c2e9..17a37ebb1 100644 --- a/src/main/java/org/scijava/command/Command.java +++ b/src/main/java/org/scijava/command/Command.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/CommandInfo.java b/src/main/java/org/scijava/command/CommandInfo.java index cdde41992..f25c213db 100644 --- a/src/main/java/org/scijava/command/CommandInfo.java +++ b/src/main/java/org/scijava/command/CommandInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/CommandModule.java b/src/main/java/org/scijava/command/CommandModule.java index fc1e59469..226edc678 100644 --- a/src/main/java/org/scijava/command/CommandModule.java +++ b/src/main/java/org/scijava/command/CommandModule.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/CommandModuleItem.java b/src/main/java/org/scijava/command/CommandModuleItem.java index 38b52ac11..079193311 100644 --- a/src/main/java/org/scijava/command/CommandModuleItem.java +++ b/src/main/java/org/scijava/command/CommandModuleItem.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/CommandService.java b/src/main/java/org/scijava/command/CommandService.java index 6e777ea5b..9cd4f5841 100644 --- a/src/main/java/org/scijava/command/CommandService.java +++ b/src/main/java/org/scijava/command/CommandService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/ContextCommand.java b/src/main/java/org/scijava/command/ContextCommand.java index 86094df90..c40649d53 100644 --- a/src/main/java/org/scijava/command/ContextCommand.java +++ b/src/main/java/org/scijava/command/ContextCommand.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/DefaultCommandService.java b/src/main/java/org/scijava/command/DefaultCommandService.java index 64ee66b62..29756debb 100644 --- a/src/main/java/org/scijava/command/DefaultCommandService.java +++ b/src/main/java/org/scijava/command/DefaultCommandService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/DynamicCommand.java b/src/main/java/org/scijava/command/DynamicCommand.java index 4d6f8e980..5cc3ab4b1 100644 --- a/src/main/java/org/scijava/command/DynamicCommand.java +++ b/src/main/java/org/scijava/command/DynamicCommand.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/DynamicCommandInfo.java b/src/main/java/org/scijava/command/DynamicCommandInfo.java index f45561e6b..06c4a16e7 100644 --- a/src/main/java/org/scijava/command/DynamicCommandInfo.java +++ b/src/main/java/org/scijava/command/DynamicCommandInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/Inputs.java b/src/main/java/org/scijava/command/Inputs.java index 291f748cb..b2f5e4217 100644 --- a/src/main/java/org/scijava/command/Inputs.java +++ b/src/main/java/org/scijava/command/Inputs.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/Interactive.java b/src/main/java/org/scijava/command/Interactive.java index cb35b9314..9714f4a6e 100644 --- a/src/main/java/org/scijava/command/Interactive.java +++ b/src/main/java/org/scijava/command/Interactive.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/InteractiveCommand.java b/src/main/java/org/scijava/command/InteractiveCommand.java index 51e7b9ffa..b45e3f21f 100644 --- a/src/main/java/org/scijava/command/InteractiveCommand.java +++ b/src/main/java/org/scijava/command/InteractiveCommand.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/ModuleCommand.java b/src/main/java/org/scijava/command/ModuleCommand.java index 5cb014814..c09ad922c 100644 --- a/src/main/java/org/scijava/command/ModuleCommand.java +++ b/src/main/java/org/scijava/command/ModuleCommand.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/Previewable.java b/src/main/java/org/scijava/command/Previewable.java index 5115b88a1..4fbeaebb9 100644 --- a/src/main/java/org/scijava/command/Previewable.java +++ b/src/main/java/org/scijava/command/Previewable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/UnimplementedCommand.java b/src/main/java/org/scijava/command/UnimplementedCommand.java index f803e283c..f1103751a 100644 --- a/src/main/java/org/scijava/command/UnimplementedCommand.java +++ b/src/main/java/org/scijava/command/UnimplementedCommand.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/console/RunArgument.java b/src/main/java/org/scijava/command/console/RunArgument.java index d066e9d74..b2529d279 100644 --- a/src/main/java/org/scijava/command/console/RunArgument.java +++ b/src/main/java/org/scijava/command/console/RunArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/command/run/CommandCodeRunner.java b/src/main/java/org/scijava/command/run/CommandCodeRunner.java index ea493609c..bc8550275 100644 --- a/src/main/java/org/scijava/command/run/CommandCodeRunner.java +++ b/src/main/java/org/scijava/command/run/CommandCodeRunner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/AbstractConsoleArgument.java b/src/main/java/org/scijava/console/AbstractConsoleArgument.java index 88d64af7a..76040544d 100644 --- a/src/main/java/org/scijava/console/AbstractConsoleArgument.java +++ b/src/main/java/org/scijava/console/AbstractConsoleArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/ConsoleArgument.java b/src/main/java/org/scijava/console/ConsoleArgument.java index 2067aae10..44d058211 100644 --- a/src/main/java/org/scijava/console/ConsoleArgument.java +++ b/src/main/java/org/scijava/console/ConsoleArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/ConsoleService.java b/src/main/java/org/scijava/console/ConsoleService.java index 97299556c..3003892a4 100644 --- a/src/main/java/org/scijava/console/ConsoleService.java +++ b/src/main/java/org/scijava/console/ConsoleService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/ConsoleUtils.java b/src/main/java/org/scijava/console/ConsoleUtils.java index 80713b5bd..2f62f0c14 100644 --- a/src/main/java/org/scijava/console/ConsoleUtils.java +++ b/src/main/java/org/scijava/console/ConsoleUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/DefaultConsoleService.java b/src/main/java/org/scijava/console/DefaultConsoleService.java index 9f474b2f7..b3a1ef64b 100644 --- a/src/main/java/org/scijava/console/DefaultConsoleService.java +++ b/src/main/java/org/scijava/console/DefaultConsoleService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/MultiOutputStream.java b/src/main/java/org/scijava/console/MultiOutputStream.java index dc2a3ec62..a8d8238fd 100644 --- a/src/main/java/org/scijava/console/MultiOutputStream.java +++ b/src/main/java/org/scijava/console/MultiOutputStream.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/MultiPrintStream.java b/src/main/java/org/scijava/console/MultiPrintStream.java index 991f24710..c27df7e9b 100644 --- a/src/main/java/org/scijava/console/MultiPrintStream.java +++ b/src/main/java/org/scijava/console/MultiPrintStream.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/OutputEvent.java b/src/main/java/org/scijava/console/OutputEvent.java index ffacdfa07..c408bcaa3 100644 --- a/src/main/java/org/scijava/console/OutputEvent.java +++ b/src/main/java/org/scijava/console/OutputEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/OutputListener.java b/src/main/java/org/scijava/console/OutputListener.java index 1486f70f0..b1543d339 100644 --- a/src/main/java/org/scijava/console/OutputListener.java +++ b/src/main/java/org/scijava/console/OutputListener.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/console/SystemPropertyArgument.java b/src/main/java/org/scijava/console/SystemPropertyArgument.java index c6a053fbc..33ba2771f 100644 --- a/src/main/java/org/scijava/console/SystemPropertyArgument.java +++ b/src/main/java/org/scijava/console/SystemPropertyArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,7 +44,7 @@ @Plugin(type = ConsoleArgument.class) public class SystemPropertyArgument extends AbstractConsoleArgument { - private static final String SYS_PROP_REGEX = "-D([\\w\\._-]+)(=(.*))?"; + private static final String SYS_PROP_REGEX = "-D([^=]+)(=(.*))?"; private static final Pattern SYS_PROP_PAT = Pattern.compile(SYS_PROP_REGEX); // -- Constructor -- diff --git a/src/main/java/org/scijava/convert/AbstractConvertService.java b/src/main/java/org/scijava/convert/AbstractConvertService.java index 89b883f63..c3a56ae47 100644 --- a/src/main/java/org/scijava/convert/AbstractConvertService.java +++ b/src/main/java/org/scijava/convert/AbstractConvertService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,151 +29,16 @@ package org.scijava.convert; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; - import org.scijava.plugin.AbstractHandlerService; -import org.scijava.util.ConversionUtils; /** - * Abstract superclass for {@link ConvertService} implementations. Sets this - * service as the active delegate service in {@link ConversionUtils}. + * Abstract superclass for {@link ConvertService} implementations. * * @author Mark Hiner */ -public abstract class AbstractConvertService extends AbstractHandlerService> - implements ConvertService { - - // -- ConversionService methods -- - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public Class> getPluginType() { - return (Class) Converter.class; - } - - @Override - public Class getType() { - return ConversionRequest.class; - } - - @Override - public Converter getHandler(final Object src, final Class dest) { - return getHandler(new ConversionRequest(src, dest)); - } - - @Override - public Converter getHandler(final Class src, final Class dest) { - return getHandler(new ConversionRequest(src, dest)); - } - - @Override - public Converter getHandler(final Object src, final Type dest) { - return getHandler(new ConversionRequest(src, dest)); - } - - @Override - public Converter getHandler(final Class src, final Type dest) { - return getHandler(new ConversionRequest(src, dest)); - } - - @Override - public boolean supports(final Object src, final Class dest) { - return supports(new ConversionRequest(src, dest)); - } - - @Override - public boolean supports(final Class src, final Class dest) { - return supports(new ConversionRequest(src, dest)); - } - - @Override - public boolean supports(final Object src, final Type dest) { - return supports(new ConversionRequest(src, dest)); - } - - @Override - public boolean supports(final Class src, final Type dest) { - return supports(new ConversionRequest(src, dest)); - } - - @Override - public Collection getCompatibleInputs(final Class dest) { - final Set objects = new LinkedHashSet<>(); - - for (final Converter c : getInstances()) { - if (dest.isAssignableFrom(c.getOutputType())) { - c.populateInputCandidates(objects); - } - } - - return objects; - } - - @Override - public Object convert(final Object src, final Type dest) { - return convert(new ConversionRequest(src, dest)); - } - - @Override - public T convert(final Object src, final Class dest) { - // NB: repeated code with convert(ConversionRequest), because the - // handler's convert method respects the T provided - final Converter handler = getHandler(src, dest); - return handler == null ? null : handler.convert(src, dest); - } - - @Override - public Object convert(final ConversionRequest request) { - final Converter handler = getHandler(request); - return handler == null ? null : handler.convert(request); - } - - @Override - public Collection> getCompatibleInputClasses(final Class dest) { - final Set> compatibleClasses = new HashSet<>(); - - for (final Converter converter : getInstances()) { - addIfMatches(dest, converter.getOutputType(), converter.getInputType(), compatibleClasses); - } - - return compatibleClasses; - } - - @Override - public Collection> getCompatibleOutputClasses(final Class source) { - final Set> compatibleClasses = new HashSet<>(); - - for (final Converter converter : getInstances()) { - try { - addIfMatches(source, converter.getInputType(), converter.getOutputType(), compatibleClasses); - } - catch (final Throwable t) { - log().error("Malfunctioning converter plugin: " + // - converter.getClass().getName(), t); - } - } - - return compatibleClasses; - } - - // -- Service methods -- - - @Override - public void initialize() { - ConversionUtils.setDelegateService(this, getPriority()); - } - - // -- Helper methods -- - - /** - * Test two classes; if they match, a third class is added to the provided - * set of classes. - */ - private void addIfMatches(final Class c1, final Class c2, final Class toAdd, final Set> classes) { - if (c1 == c2) - classes.add(toAdd); - } +public abstract class AbstractConvertService // + extends AbstractHandlerService> // + implements ConvertService +{ + // NB: This layer remains merely for backwards compatibility. } diff --git a/src/main/java/org/scijava/convert/AbstractConverter.java b/src/main/java/org/scijava/convert/AbstractConverter.java index 9b2ae2cda..c6132c396 100644 --- a/src/main/java/org/scijava/convert/AbstractConverter.java +++ b/src/main/java/org/scijava/convert/AbstractConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,37 +29,17 @@ package org.scijava.convert; -import java.lang.reflect.Type; import java.util.Collection; import org.scijava.object.ObjectService; import org.scijava.plugin.AbstractHandlerPlugin; import org.scijava.plugin.Parameter; -import org.scijava.util.Types; /** * Abstract superclass for {@link Converter} plugins. Performs appropriate * dispatching of {@link #canConvert(ConversionRequest)} and * {@link #convert(ConversionRequest)} calls based on the actual state of the * given {@link ConversionRequest}. - *

- * Note that the {@link #supports(ConversionRequest)} method is overridden as - * well, to delegate to the appropriate {@link #canConvert}. - *

- *

- * NB: by default, the {@link #populateInputCandidates(Collection)} method has a - * dummy implementation. Effectively, this is opt-in behavior. If a converter - * implementation would like to suggest candidates for conversion, this method - * can be overridden. - *

- *

- * NB: by default, the provied {@link #canConvert} methods will return - * {@code false} if the input is {@code null}. This allows {@link Converter} - * implementors to assume any input is non-{@code null} - but this behavior is - * overridden. Casting {@code null Object} inputs is handled by the - * {@link NullConverter}, while {@code null class} inputs are handled by the - * {@link DefaultConverter}. - *

* * @author Mark Hiner */ @@ -72,59 +52,7 @@ public abstract class AbstractConverter extends @Parameter(required = false) private ObjectService objectService; - // -- ConversionHandler methods -- - - @Override - public boolean canConvert(final ConversionRequest request) { - Object src = request.sourceObject(); - if (src == null) { - Class srcClass = request.sourceClass(); - if (request.destType() != null) return canConvert(srcClass, request.destType()); - return canConvert(srcClass, request.destClass()); - } - - if (request.destType() != null) return canConvert(src, request.destType()); - return canConvert(src, request.destClass()); - } - - @Override - public boolean canConvert(final Object src, final Type dest) { - if (src == null) return false; - final Class srcClass = src.getClass(); - return canConvert(srcClass, dest); - } - - @Override - public boolean canConvert(final Object src, final Class dest) { - if (src == null) return false; - final Class srcClass = src.getClass(); - - return canConvert(srcClass, dest); - } - - @Override - public boolean canConvert(final Class src, final Class dest) { - if (src == null) return false; - final Class saneSrc = Types.box(src); - final Class saneDest = Types.box(dest); - return Types.isAssignable(saneSrc, getInputType()) && - Types.isAssignable(getOutputType(), saneDest); - } - - @Override - public Object convert(final Object src, final Type dest) { - final Class destClass = Types.raw(dest); - return convert(src, destClass); - } - - @Override - public Object convert(final ConversionRequest request) { - if (request.destType() != null) { - return convert(request.sourceObject(), request.destType()); - } - - return convert(request.sourceObject(), request.destClass()); - } + // -- Converter methods -- @Override public void populateInputCandidates(final Collection objects) { @@ -138,20 +66,8 @@ public void populateInputCandidates(final Collection objects) { @Override public boolean supports(final ConversionRequest request) { - return canConvert(request); - } - - @Override - public Class getType() { - return ConversionRequest.class; - } - - // -- Deprecated API -- - - @Override - @Deprecated - public boolean canConvert(final Class src, final Type dest) { - final Class destClass = Types.raw(dest); - return canConvert(src, destClass); + // NB: Overridden just for backwards compatibility, so that + // downstream classes which call super.supports do the right thing. + return Converter.super.supports(request); } } diff --git a/src/main/java/org/scijava/convert/AbstractDelegateConverter.java b/src/main/java/org/scijava/convert/AbstractDelegateConverter.java index 4e447eb79..97b8b23ea 100644 --- a/src/main/java/org/scijava/convert/AbstractDelegateConverter.java +++ b/src/main/java/org/scijava/convert/AbstractDelegateConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/ArrayConverters.java b/src/main/java/org/scijava/convert/ArrayConverters.java index 507ff693e..0c16551a0 100644 --- a/src/main/java/org/scijava/convert/ArrayConverters.java +++ b/src/main/java/org/scijava/convert/ArrayConverters.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/ArrayToStringConverter.java b/src/main/java/org/scijava/convert/ArrayToStringConverter.java new file mode 100644 index 000000000..e1e3ce96b --- /dev/null +++ b/src/main/java/org/scijava/convert/ArrayToStringConverter.java @@ -0,0 +1,128 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.convert; + +import java.lang.reflect.Array; +import java.lang.reflect.Type; +import java.util.stream.Collectors; + +import org.scijava.Priority; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.util.ArrayUtils; + +/** + * A {@link Converter} that specializes in converting n-dimensional arrays into + * {@link String}s. This {@link Converter} can convert any array whose component + * types can be converted into {@link String}s. By default, this + * {@link Converter} delimits the array elements with commas. + * + * @author Gabriel Selzer + */ +@Plugin(type = Converter.class, priority = Priority.VERY_LOW) +public class ArrayToStringConverter extends AbstractConverter { + + @Parameter(required = false) + private ConvertService convertService; + + @Override + public boolean canConvert(final Class src, final Class dest) { + return src != null && src.isArray() && dest == String.class; + } + + @Override + public boolean canConvert(final Object src, final Class dest) { + if (convertService == null || src == null) return false; + if (!canConvert(src.getClass(), dest)) return false; + if (Array.getLength(src) == 0) return true; + return convertService.supports(Array.get(src, 0), dest); + } + + @Override + public Object convert(Object src, final Type dest) { + // Preprocess the "string-likes" + final Class srcClass = src.getClass(); + if (srcClass == String[].class || // + srcClass == Character[].class || // + srcClass == char[].class) // + { + src = preprocessCharacters(src); + } + // Convert each element to Strings + final String elementString = ArrayUtils.toCollection(src).stream() // + .map(object -> convertService.convert(object, String.class)) // + .collect(Collectors.joining(", ")); + return "{" + elementString + "}"; + } + + private String[] preprocessStrings(final Object src) { + final int numElements = Array.getLength(src); + final String[] processed = new String[numElements]; + for (int i = 0; i < numElements; i++) { + processed[i] = preprocessString(Array.get(src, i)); + } + return processed; + } + + private String preprocessString(final Object o) { + if (o == null) return null; + String s = o.toString(); + s = s.replace("\\", "\\\\"); + s = s.replace("\"", "\\\""); + return "\"" + s + "\""; + } + + private String[] preprocessCharacters(Object src) { + final String[] processed = new String[Array.getLength(src)]; + for (int i = 0; i < processed.length; i++) { + final Object value = Array.get(src, i); + processed[i] = value == null ? null : value.toString(); + } + return preprocessStrings(processed); + } + + @Override + public T convert(final Object src, final Class dest) { + final Type destType = dest; + @SuppressWarnings("unchecked") + final T converted = (T) convert(src, destType); + return converted; + } + + @Override + public Class getOutputType() { + return String.class; + } + + @Override + public Class getInputType() { + return Object.class; + } +} diff --git a/src/main/java/org/scijava/convert/CastingConverter.java b/src/main/java/org/scijava/convert/CastingConverter.java index d55b9663a..3b5a4e91f 100644 --- a/src/main/java/org/scijava/convert/CastingConverter.java +++ b/src/main/java/org/scijava/convert/CastingConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,6 +28,8 @@ */ package org.scijava.convert; +import java.lang.reflect.Type; + import org.scijava.Priority; import org.scijava.plugin.Plugin; import org.scijava.util.Types; @@ -37,7 +39,7 @@ * * @author Mark Hiner */ -@Plugin(type = Converter.class, priority = Priority.EXTREMELY_HIGH) +@Plugin(type = Converter.class, priority = Priority.EXTREMELY_HIGH - 1) public class CastingConverter extends AbstractConverter { @Override @@ -45,26 +47,37 @@ public boolean canConvert(final Object src, final Class dest) { return Types.isInstance(src, dest); } + @Override + public boolean canConvert(final Class src, final Type dest) { + // NB: You might think we want to use Types.isAssignable(src, dest) + // directly here. And you might be right. However, assignment involving + // generic types gets very tricky. If dest is e.g. a wildcard type such as + // "? extends Object", or a type variable such as "C extends Object", then + // no specific class will be assignable to it, because for that ? or C we + // do not know anything about the bound type other than that it's something + // that extends Object, so it could be anything, including things that + // aren't assignable from whatever src is. + // + // Unfortunately, when this casting conversion code was originally written, + // it did not have generics in mind, and calling code will pass in capture + // types (e.g. Type objects gleaned via ModuleItem#getGenericType()) + // expecting them to be convertible as long as dest's raw type(s) are + // compatible targets for src. + // + // And so for backwards compatibility, we continue to behave that way here. + + return dest != null && // + Types.raws(dest).stream().allMatch(c -> c.isAssignableFrom(src)); + } + @Override public boolean canConvert(final Class src, final Class dest) { - // OK if the existing object can be casted - return dest != null && Types.isAssignable(src, dest); + return dest != null && dest.isAssignableFrom(src); } - @SuppressWarnings("unchecked") @Override public T convert(final Object src, final Class dest) { - // NB: Regardless of whether the destination type is an array or - // collection, we still want to cast directly if doing so is possible. - // But note that in general, this check does not detect cases of - // incompatible generic parameter types. If this limitation becomes a - // problem in the future we can extend the logic here to provide - // additional signatures of canCast which operate on Types in general - // rather than only Classes. However, the logic could become complex - // very quickly in various subclassing cases, generic parameters - // resolved vs. propagated, etc. - final Class c = Types.raw(dest); - return (T) Types.cast(src, c); + return Types.cast(src, dest); } @Override diff --git a/src/main/java/org/scijava/convert/ConversionRequest.java b/src/main/java/org/scijava/convert/ConversionRequest.java index 36fc745a9..c4ee0fd2b 100644 --- a/src/main/java/org/scijava/convert/ConversionRequest.java +++ b/src/main/java/org/scijava/convert/ConversionRequest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/ConvertService.java b/src/main/java/org/scijava/convert/ConvertService.java index f82552970..ff3309baf 100644 --- a/src/main/java/org/scijava/convert/ConvertService.java +++ b/src/main/java/org/scijava/convert/ConvertService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,14 +31,17 @@ import java.lang.reflect.Type; import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; import org.scijava.plugin.HandlerService; import org.scijava.service.SciJavaService; /** - * Service for converting between types using an extensible plugin: - * {@link Converter}. Contains convenience signatures for the - * {@link #getHandler} and {@link #supports} methods to avoid the need to create + * Service for converting between types using an {@link Converter} plugins. + * Contains convenience signatures for the {@link #getHandler} and + * {@link #supports} methods to avoid the need to create * {@link ConversionRequest} objects. * * @see ConversionRequest @@ -51,83 +54,148 @@ public interface ConvertService extends /** * @see Converter#convert(Object, Type) */ - Object convert(Object src, Type dest); + default Object convert(final Object src, final Type dest) { + return convert(new ConversionRequest(src, dest)); + } /** * @see Converter#convert(Object, Class) */ - T convert(Object src, Class dest); + default T convert(final Object src, final Class dest) { + // NB: repeated code with convert(ConversionRequest), because the + // handler's convert method respects the T provided + final Converter handler = getHandler(src, dest); + return handler == null ? null : handler.convert(src, dest); + } /** * @see Converter#convert(ConversionRequest) */ - Object convert(ConversionRequest request); + default Object convert(final ConversionRequest request) { + final Converter handler = getHandler(request); + return handler == null ? null : handler.convert(request); + } /** * @see HandlerService#supports(Object) */ - Converter getHandler(Object src, Class dest); + default Converter getHandler(final Object src, final Type dest) { + return getHandler(new ConversionRequest(src, dest)); + } /** * @see HandlerService#supports(Object) */ - Converter getHandler(Object src, Type dest); + default Converter getHandler(final Object src, final Class dest) { + return getHandler(new ConversionRequest(src, dest)); + } /** - * @see HandlerService#supports(Object) + * @see HandlerService#getHandler(Object) */ - boolean supports(Object src, Class dest); + default Converter getHandler(final Class src, final Type dest) { + return getHandler(new ConversionRequest(src, dest)); + } /** - * @see HandlerService#supports(Object) + * @see HandlerService#getHandler(Object) */ - boolean supports(Object src, Type dest); + default Converter getHandler(final Class src, final Class dest) { + return getHandler(new ConversionRequest(src, dest)); + } /** - * @return A collection of instances that could be converted to the - * specified class. + * @see HandlerService#supports(Object) */ - Collection getCompatibleInputs(Class dest); + default boolean supports(final Object src, final Type dest) { + return supports(new ConversionRequest(src, dest)); + } /** - * @return A collection of all classes that could potentially be converted - * to the specified class. + * @see HandlerService#supports(Object) */ - Collection> getCompatibleInputClasses(Class dest); + default boolean supports(final Object src, final Class dest) { + return supports(new ConversionRequest(src, dest)); + } /** - * @return A collection of all classes that could potentially be converted - * from the specified class. + * @see HandlerService#supports(Object) */ - Collection> getCompatibleOutputClasses(Class dest); - - // -- Deprecated API -- + default boolean supports(final Class src, final Type dest) { + return supports(new ConversionRequest(src, dest)); + } /** - * @see HandlerService#getHandler(Object) - * @deprecated Use {@link #getHandler(Object, Class)} + * @see HandlerService#supports(Object) */ - @Deprecated - Converter getHandler(Class src, Class dest); + default boolean supports(final Class src, final Class dest) { + return supports(new ConversionRequest(src, dest)); + } /** - * @see HandlerService#getHandler(Object) - * @deprecated Use {@link #getHandler(Object, Type)} + * @return A collection of instances that could be converted to the + * specified class. */ - @Deprecated - Converter getHandler(Class src, Type dest); + default Collection getCompatibleInputs(final Class dest) { + final Set objects = new LinkedHashSet<>(); + + for (final Converter c : getInstances()) { + if (dest.isAssignableFrom(c.getOutputType())) { + c.populateInputCandidates(objects); + } + } + + return objects; + } /** - * @see HandlerService#supports(Object) - * @deprecated Use {@link #supports(Object, Class)} + * @return A collection of all classes that could potentially be converted + * to the specified class. */ - @Deprecated - boolean supports(Class src, Class dest); + default Collection> getCompatibleInputClasses(final Class dest) { + final Set> compatibleClasses = new HashSet<>(); + + for (final Converter converter : getInstances()) { + if (dest == converter.getOutputType()) // + compatibleClasses.add(converter.getInputType()); + } + + return compatibleClasses; + } /** - * @see HandlerService#supports(Object) - * @deprecated Use {@link #supports(Object, Type)} + * @return A collection of all classes that could potentially be converted + * from the specified class. */ - @Deprecated - boolean supports(Class src, Type dest); + default Collection> getCompatibleOutputClasses(final Class source) { + final Set> compatibleClasses = new HashSet<>(); + + for (final Converter converter : getInstances()) { + try { + if (source == converter.getInputType()) // + compatibleClasses.add(converter.getOutputType()); + } + catch (final Throwable t) { + log().error("Malfunctioning converter plugin: " + // + converter.getClass().getName(), t); + } + } + + return compatibleClasses; + } + + // -- PTService methods -- + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + default Class> getPluginType() { + return (Class) Converter.class; + } + + // -- Typed methods -- + + @Override + default Class getType() { + return ConversionRequest.class; + } } diff --git a/src/main/java/org/scijava/convert/Converter.java b/src/main/java/org/scijava/convert/Converter.java index bf63a19d8..1578a96dd 100644 --- a/src/main/java/org/scijava/convert/Converter.java +++ b/src/main/java/org/scijava/convert/Converter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,15 +32,24 @@ import java.lang.reflect.Type; import java.util.Collection; import java.util.List; +import java.util.Queue; import java.util.Set; import org.scijava.object.ObjectService; import org.scijava.plugin.HandlerPlugin; import org.scijava.plugin.Plugin; +import org.scijava.util.Types; /** * Extensible conversion {@link Plugin} for converting between classes and * types. + *

+ * NB: by default, the provided {@link #canConvert} methods will return + * {@code false} if the input is {@code null}. This allows {@link Converter} + * implementors to assume any input is non-{@code null}. Casting + * {@code null Object} inputs is handled by the {@link NullConverter}, while + * {@code null} class inputs are handled by the {@link DefaultConverter}. + *

* * @see ConversionRequest * @author Mark Hiner @@ -55,41 +64,107 @@ public interface Converter extends HandlerPlugin { * * @see #convert(ConversionRequest) */ - boolean canConvert(ConversionRequest request); + default boolean canConvert(final ConversionRequest request) { + if (request == null) return false; + final Object src = request.sourceObject(); + final Type destType = request.destType(); + if (src != null && destType != null) { + return canConvert(src, destType); + } + if (src != null) { + return canConvert(src, request.destClass()); + } + if (destType != null) { + return canConvert(request.sourceClass(), destType); + } + return canConvert(request.sourceClass(), request.destClass()); + } /** * Checks whether the given object's type can be converted to the specified * type. + * + * @see #convert(Object, Type) + */ + default boolean canConvert(final Object src, final Type dest) { + if (src == null || dest == null) return false; + return canConvert(src.getClass(), dest); + } + + /** + * Checks whether the given object's type can be converted to the specified + * type. + * + * @see #convert(Object, Class) + */ + default boolean canConvert(final Object src, final Class dest) { + if (src == null) return false; + Class srcClass = src.getClass(); + return canConvert(srcClass, dest); + } + + /** + * Checks whether objects of the given class can be converted to the specified + * type. *

* Note that this does not necessarily entail that - * {@link #convert(Object, Type)} on that specific object will succeed. For - * example: {@code canConvert("5.1", int.class)} will return {@code true} - * because a {@link String} can in general be converted to an {@code int}, but - * calling {@code convert("5.1", int.class)} will throw a + * {@link #convert(Object, Type)} on a specific object of the given source + * class will succeed. For example: + * {@code canConvert(String.class, List)} will return {@code true} + * because a {@link String} can in general be converted to an {@code Integer} + * and then wrapped into a {@code List}, but calling + * {@code convert("5.1", List)} will throw a * {@link NumberFormatException} when the conversion is actually attempted via * the {@link Integer#Integer(String)} constructor. *

- * + * * @see #convert(Object, Type) */ - boolean canConvert(Object src, Type dest); + default boolean canConvert(final Class src, final Type dest) { + final Class destClass = Types.raw(dest); + return canConvert(src, destClass); + } /** - * Checks whether the given object's type can be converted to the specified + * Checks whether objects of the given class can be converted to the specified * type. *

* Note that this does not necessarily entail that - * {@link #convert(Object, Class)} on that specific object will succeed. For - * example: {@code canConvert("5.1", int.class)} will return {@code true} + * {@link #convert(Object, Class)} on a specific object of the given source + * class will succeed. For example: + * {@code canConvert(String.class, int.class)} will return {@code true} * because a {@link String} can in general be converted to an {@code int}, but * calling {@code convert("5.1", int.class)} will throw a * {@link NumberFormatException} when the conversion is actually attempted via * the {@link Integer#Integer(String)} constructor. *

+ * + * @see #convert(Object, Class) + */ + default boolean canConvert(final Class src, final Class dest) { + if (src == null) return false; + final Class saneSrc = Types.box(src); + final Class saneDest = Types.box(dest); + return Types.isAssignable(saneSrc, getInputType()) && // + Types.isAssignable(getOutputType(), saneDest); + } + + /** + * Converts the given {@link ConversionRequest#sourceObject()} to the + * specified {@link ConversionRequest#destClass()} or + * {@link ConversionRequest#destType()}. * * @see #convert(Object, Class) + * @see #convert(Object, Type) + * @param request {@link ConversionRequest} to process. + * @return The conversion output */ - boolean canConvert(Object src, Class dest); + default Object convert(final ConversionRequest request) { + if (request.destType() != null) { + return convert(request.sourceObject(), request.destType()); + } + return convert(request.sourceObject(), request.destClass()); + } /** * As {@link #convert(Object, Class)} but capable of creating and populating @@ -102,14 +177,17 @@ public interface Converter extends HandlerPlugin { *

* NB: This method should be capable of creating any array type, but if a * {@link Collection} interface or abstract class is provided we can only make - * a best guess as to what container type to instantiate. Defaults are - * provided for {@link Set} and {@link List} subclasses. + * a best guess as to what container type to instantiate; defaults are + * provided for {@link Set}, {@link Queue}, and {@link List}. *

* * @param src The object to convert. * @param dest Type to which the object should be converted. */ - Object convert(Object src, Type dest); + default Object convert(final Object src, final Type dest) { + final Class destClass = Types.raw(dest); + return convert(src, destClass); + } /** * Converts the given object to an object of the specified type. The object is @@ -126,18 +204,6 @@ public interface Converter extends HandlerPlugin { */ T convert(Object src, Class dest); - /** - * Converts the given {@link ConversionRequest#sourceObject()} to the - * specified {@link ConversionRequest#destClass()} or - * {@link ConversionRequest#destType()}. - * - * @see #convert(Object, Class) - * @see #convert(Object, Type) - * @param request {@link ConversionRequest} to process. - * @return The conversion output - */ - Object convert(ConversionRequest request); - /** * Populates the given collection with objects which are known to exist, and * which are usable as inputs for this converter. @@ -170,25 +236,15 @@ public interface Converter extends HandlerPlugin { */ Class getInputType(); - // -- Deprecated API -- + // -- Typed methods -- - /** - * Checks whether objects of the given class can be converted to the specified - * type. - * - * @see #convert(Object, Type) - * @deprecated Use {@link #canConvert(Object, Type)} - */ - @Deprecated - boolean canConvert(Class src, Type dest); + @Override + default boolean supports(final ConversionRequest request) { + return canConvert(request); + } - /** - * Checks whether objects of the given class can be converted to the specified - * type. - * - * @see #convert(Object, Class) - * @deprecated Use {@link #canConvert(Object, Class)} - */ - @Deprecated - boolean canConvert(Class src, Class dest); + @Override + default Class getType() { + return ConversionRequest.class; + } } diff --git a/src/main/java/org/scijava/convert/DefaultConvertService.java b/src/main/java/org/scijava/convert/DefaultConvertService.java index bb5ec9d50..2ddd292ad 100644 --- a/src/main/java/org/scijava/convert/DefaultConvertService.java +++ b/src/main/java/org/scijava/convert/DefaultConvertService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,5 +40,5 @@ @Plugin(type = Service.class) public class DefaultConvertService extends AbstractConvertService { - // Trivial implementation + // NB: No implementation needed. } diff --git a/src/main/java/org/scijava/convert/DefaultConverter.java b/src/main/java/org/scijava/convert/DefaultConverter.java index d2daea418..c99c5a889 100644 --- a/src/main/java/org/scijava/convert/DefaultConverter.java +++ b/src/main/java/org/scijava/convert/DefaultConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,19 +31,21 @@ import java.lang.reflect.Array; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; +import java.util.Deque; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Queue; import java.util.Set; import org.scijava.Priority; import org.scijava.plugin.Plugin; import org.scijava.util.ArrayUtils; -import org.scijava.util.ConversionUtils; import org.scijava.util.Types; /** @@ -73,6 +75,11 @@ public class DefaultConverter extends AbstractConverter { @Override public Object convert(final Object src, final Type dest) { + // special case: CharSequence -> char[] + // otherwise, String -> char[] ends up length 1 with first char only + if (src instanceof CharSequence && dest == char[].class) { + return ((CharSequence) src).toString().toCharArray(); + } // Handle array types, including generic array types. final Type componentType = Types.component(dest); @@ -81,66 +88,34 @@ public Object convert(final Object src, final Type dest) { return convertToArray(src, Types.raw(componentType)); } - // Handle parameterized collection types. - if (dest instanceof ParameterizedType && isCollection(dest)) { - return convertToCollection(src, (ParameterizedType) dest); + // Handle collection types, either raw or parameterized. + Class cClass = collectionClass(dest); + if (cClass != null) { + Type elementType = Types.param(dest, Collection.class, 0); + if (elementType == null) elementType = Object.class; // raw collection + final Object collection = convertToCollection(src, cClass, elementType); + if (collection != null) return collection; + // NB: If this conversion failed, it might still succeed later + // when looking for a wrapping constructor. So let's keep going. + // In particular, see ConvertServiceTest#testConvertSubclass(). } - // This wasn't a collection or array, so convert it as a single element. - return convert(src, Types.raw(dest)); - } + // Ensure type is a well-behaved class, rather than a primitive type. + final Class destClass = Types.raw(dest); + final Class saneDest = Types.box(destClass); - @Override - public T convert(final Object src, final Class dest) { - // ensure type is well-behaved, rather than a primitive type - final Class saneDest = Types.box(dest); - - // Handle array types - if (isArray(dest)) { - @SuppressWarnings("unchecked") - T array = (T) convertToArray(src, Types.raw(Types.component(dest))); - return array; - } + // Object is already the requested type. + if (Types.isInstance(src, saneDest)) return src; // special case for conversion from number to number if (src instanceof Number) { final Number number = (Number) src; - if (saneDest == Byte.class) { - final Byte result = number.byteValue(); - @SuppressWarnings("unchecked") - final T typedResult = (T) result; - return typedResult; - } - if (saneDest == Double.class) { - final Double result = number.doubleValue(); - @SuppressWarnings("unchecked") - final T typedResult = (T) result; - return typedResult; - } - if (saneDest == Float.class) { - final Float result = number.floatValue(); - @SuppressWarnings("unchecked") - final T typedResult = (T) result; - return typedResult; - } - if (saneDest == Integer.class) { - final Integer result = number.intValue(); - @SuppressWarnings("unchecked") - final T typedResult = (T) result; - return typedResult; - } - if (saneDest == Long.class) { - final Long result = number.longValue(); - @SuppressWarnings("unchecked") - final T typedResult = (T) result; - return typedResult; - } - if (saneDest == Short.class) { - final Short result = number.shortValue(); - @SuppressWarnings("unchecked") - final T typedResult = (T) result; - return typedResult; - } + if (saneDest == Byte.class) return number.byteValue(); + if (saneDest == Double.class) return number.doubleValue(); + if (saneDest == Float.class) return number.floatValue(); + if (saneDest == Integer.class) return number.intValue(); + if (saneDest == Long.class) return number.longValue(); + if (saneDest == Short.class) return number.shortValue(); } // special cases for strings @@ -149,46 +124,55 @@ public T convert(final Object src, final Class dest) { final String s = (String) src; if (s.isEmpty()) { // return null for empty strings - return Types.nullValue(dest); + return Types.nullValue(saneDest); } // use first character when converting to Character if (saneDest == Character.class) { - final Character c = new Character(s.charAt(0)); - @SuppressWarnings("unchecked") - final T result = (T) c; - return result; + return new Character(s.charAt(0)); } // special case for conversion to enum - if (dest.isEnum()) { - final T result = ConversionUtils.convertToEnum(s, dest); - if (result != null) return result; + if (saneDest.isEnum()) { + try { + return Types.enumFromString(s, saneDest); + } + catch (final IllegalArgumentException exc) { + // NB: No action needed. + } } } + if (saneDest == String.class) { // destination type is String; use Object.toString() method - final String sValue = src.toString(); - @SuppressWarnings("unchecked") - final T result = (T) sValue; - return result; + return src.toString(); } // wrap the original object with one of the new type, using a constructor try { final Constructor ctor = getConstructor(saneDest, src.getClass()); if (ctor == null) return null; - @SuppressWarnings("unchecked") - final T instance = (T) ctor.newInstance(src); - return instance; + return ctor.newInstance(src); } - catch (final Exception exc) { - // TODO: Best not to catch blanket Exceptions here. + catch (final InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException exc) + { // no known way to convert - return null; + return Types.nullValue(destClass); } } + @Override + public T convert(final Object src, final Class dest) { + // NB: Invert functional flow from Converter interface: + // Converter: convert(Class, Type) calling convert(Class, Class) + // becomes: convert(Class, Class) calling convert(Class, Type) + final Type destType = dest; + @SuppressWarnings("unchecked") + final T result = (T) convert(src, destType); + return result; + } + @Override public Class getOutputType() { return Object.class; @@ -219,8 +203,10 @@ private boolean isArray(final Type type) { return Types.component(type) != null; } - private boolean isCollection(final Type type) { - return Types.isAssignable(Types.raw(type), Collection.class); + private Class collectionClass(final Type type) { + return Types.raws(type).stream() // + .filter(t -> Types.isAssignable(t, Collection.class)) // + .findFirst().orElse(null); } private Object @@ -244,34 +230,32 @@ private boolean isCollection(final Type type) { } private Object convertToCollection(final Object value, - final ParameterizedType pType) + final Class collectionType, final Type elementType) { - final Collection collection = createCollection(Types.raw(pType)); + final Collection collection = createCollection(collectionType); if (collection == null) return null; // Populate the collection. final Collection items = ArrayUtils.toCollection(value); - // TODO: The following can fail; e.g. "Foo extends ArrayList" - final Type collectionType = pType.getActualTypeArguments()[0]; for (final Object item : items) { - collection.add(convert(item, collectionType)); + collection.add(convert(item, elementType)); } return collection; } - private Collection createCollection(final Class type) { - // If we were given an interface or abstract class, and not a concrete - // class, we attempt to make default implementations. - if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) { - // We don't have a concrete class. If it's a set or a list, we use - // the typical default implementation. Otherwise we won't convert. - if (Types.isAssignable(type, List.class)) return new ArrayList<>(); - if (Types.isAssignable(type, Set.class)) return new HashSet<>(); + private Collection createCollection(Class type) { + // Support conversion to common collection interface types. + if (type == Queue.class || type == Deque.class) type = ArrayDeque.class; + else if (type == Set.class) type = LinkedHashSet.class; + else if (type == List.class || type == Collection.class) type = ArrayList.class; + else if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) { + // We were given an interface or abstract class, and not a concrete + // class, and we don't know what default implementation to use. return null; } - // Got a concrete type. Instantiate it. + // We now have a concrete type. Instantiate it. try { @SuppressWarnings("unchecked") final Collection c = (Collection) type.newInstance(); @@ -288,56 +272,37 @@ private Collection createCollection(final Class type) { // -- Deprecated API -- @Override - @Deprecated - public boolean canConvert(final Class src, final Type dest) { - - // Handle array types, including generic array types. + public boolean canConvert(final Class src, final Class dest) { + // OK for array and collection types. if (isArray(dest)) return true; + Class cClass = collectionClass(dest); + if (cClass != null && createCollection(cClass) != null) return true; - // Handle parameterized collection types. - if (dest instanceof ParameterizedType && isCollection(dest) && - createCollection(Types.raw(dest)) != null) - { - return true; - } - - return super.canConvert(src, dest); - } - - @Override - @Deprecated - public boolean canConvert(final Class src, final Class dest) { // ensure type is well-behaved, rather than a primitive type final Class saneDest = Types.box(dest); // OK for numerical conversions if (Types.isAssignable(Types.box(src), Number.class) && // - (Types.isByte(dest) || Types.isDouble(dest) || Types.isFloat(dest) || - Types.isInteger(dest) || Types.isLong(dest) || Types.isShort(dest))) + (Types.isByte(saneDest) || Types.isDouble(saneDest) || // + Types.isFloat(saneDest) || Types.isInteger(saneDest) || // + Types.isLong(saneDest) || Types.isShort(saneDest))) { return true; } - + // OK if string if (saneDest == String.class) return true; - + if (Types.isAssignable(src, String.class)) { // OK if source type is string and destination type is character // (in this case, the first character of the string would be used) if (saneDest == Character.class) return true; - + // OK if source type is string and destination type is an enum if (dest.isEnum()) return true; } - + // OK if appropriate wrapper constructor exists - try { - return getConstructor(saneDest, src) != null; - } - catch (final Exception exc) { - // TODO: Best not to catch blanket Exceptions here. - // no known way to convert - return false; - } + return getConstructor(saneDest, src) != null; } } diff --git a/src/main/java/org/scijava/convert/FileListConverters.java b/src/main/java/org/scijava/convert/FileListConverters.java index 5aad27fb1..8b5d86b73 100644 --- a/src/main/java/org/scijava/convert/FileListConverters.java +++ b/src/main/java/org/scijava/convert/FileListConverters.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,7 +35,6 @@ import java.util.List; import java.util.stream.Collectors; -import org.scijava.Priority; import org.scijava.plugin.Plugin; import org.scijava.util.StringUtils; @@ -49,7 +48,7 @@ public class FileListConverters { // -- String to File (list) converters -- - @Plugin(type = Converter.class, priority = Priority.NORMAL) + @Plugin(type = Converter.class) public static class StringToFileConverter extends AbstractConverter { @@ -72,7 +71,7 @@ public Class getInputType() { } - @Plugin(type = Converter.class, priority = Priority.NORMAL) + @Plugin(type = Converter.class) public static class StringToFileArrayConverter extends AbstractConverter { @@ -83,6 +82,8 @@ public T convert(final Object src, final Class dest) { final String[] tokens = StringUtils.splitUnquoted((String) src, ","); final List fileList = new ArrayList<>(); for (final String filePath : tokens) { + if ( filePath.isEmpty() ) + continue; fileList.add(new File(filePath.replaceAll("^\"|\"$", ""))); } return (T) fileList.toArray(new File[fileList.size()]); @@ -104,7 +105,7 @@ public Class getInputType() { // -- File (list) to String converters -- - @Plugin(type = Converter.class, priority = Priority.NORMAL) + @Plugin(type = Converter.class) public static class FileToStringConverter extends AbstractConverter { @@ -127,7 +128,7 @@ public Class getInputType() { } - @Plugin(type = Converter.class, priority = Priority.NORMAL) + @Plugin(type = Converter.class) public static class FileArrayToStringConverter extends AbstractConverter { diff --git a/src/main/java/org/scijava/convert/FileToPathConverter.java b/src/main/java/org/scijava/convert/FileToPathConverter.java new file mode 100644 index 000000000..9c8717286 --- /dev/null +++ b/src/main/java/org/scijava/convert/FileToPathConverter.java @@ -0,0 +1,61 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.convert; + +import java.io.File; +import java.nio.file.Path; + +import org.scijava.plugin.Plugin; + +/** + * A {@link Converter} used to convert {@link File}s into {@link Path}s. + * + * @author Gabriel Selzer + */ +@Plugin(type = Converter.class) +public class FileToPathConverter extends AbstractConverter { + + @SuppressWarnings("unchecked") + @Override + public T convert(final Object src, final Class dest) { + File f = (File) src; + return (T) f.toPath(); + } + + @Override + public Class getOutputType() { + return Path.class; + } + + @Override + public Class getInputType() { + return File.class; + } +} diff --git a/src/main/java/org/scijava/convert/NullConverter.java b/src/main/java/org/scijava/convert/NullConverter.java index 594468617..5c91943db 100644 --- a/src/main/java/org/scijava/convert/NullConverter.java +++ b/src/main/java/org/scijava/convert/NullConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,54 +36,44 @@ import org.scijava.util.Types; /** - * {@link Converter} implementation for handling {@code null} values. Performs - * basic casting when given a {@code null} source and returns {@code null} - * directly when given a {@code null} destination. + * {@link Converter} implementation for handling {@code null} values. Returns + * {@code null} when given a {@code null} source or {@code null} destination. *

- * By running at {@link Priority#FIRST}, other converters should - * not need to worry about {@code null} source or destination parameters. - *

- *

- * NB: if a {@link Class} source is queried for the {@link #canConvert}, - * this converter will always return false (as there is no way of knowing - * if the source object will be null or not). + * By running at {@link Priority#EXTREMELY_HIGH}, other converters should not + * need to worry about {@code null} source or destination parameters. *

* * @author Mark Hiner */ -@Plugin(type = Converter.class, priority = Priority.FIRST) +@Plugin(type = Converter.class, priority = Priority.EXTREMELY_HIGH) public class NullConverter extends AbstractConverter { @Override - public boolean canConvert(final ConversionRequest request) { - if (request == null) return false; - return (request.destType() == null && request.destClass() == null) || - (request.sourceObject() == null && request.sourceClass() == null); + public boolean canConvert(final Object src, final Type dest) { + return src == null || dest == null; } @Override - public boolean canConvert(final Object src, final Type dest) { + public boolean canConvert(final Object src, final Class dest) { return src == null || dest == null; } @Override - public boolean canConvert(final Object src, final Class dest) { + public boolean canConvert(final Class src, final Type dest) { return src == null || dest == null; } @Override public boolean canConvert(final Class src, final Class dest) { - if (src == null) return false; - return dest == null; + return src == null || dest == null; } @Override public T convert(final Object src, final Class dest) { if (dest == null) return null; if (src == null) return Types.nullValue(dest); - throw new IllegalArgumentException("Attempting non-null conversion: " + - src + " > " + dest + " using NullConverter."); + src + " -> " + dest + " using NullConverter."); } @Override @@ -95,5 +85,4 @@ public Class getOutputType() { public Class getInputType() { return Object.class; } - } diff --git a/src/main/java/org/scijava/convert/NumberConverters.java b/src/main/java/org/scijava/convert/NumberConverters.java index d2d23e617..4046d6503 100644 --- a/src/main/java/org/scijava/convert/NumberConverters.java +++ b/src/main/java/org/scijava/convert/NumberConverters.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/NumberToBigDecimalConverter.java b/src/main/java/org/scijava/convert/NumberToBigDecimalConverter.java index 1b646057d..910d5a02a 100644 --- a/src/main/java/org/scijava/convert/NumberToBigDecimalConverter.java +++ b/src/main/java/org/scijava/convert/NumberToBigDecimalConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/NumberToBigIntegerConverter.java b/src/main/java/org/scijava/convert/NumberToBigIntegerConverter.java index b2f29f89d..ba3279439 100644 --- a/src/main/java/org/scijava/convert/NumberToBigIntegerConverter.java +++ b/src/main/java/org/scijava/convert/NumberToBigIntegerConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/NumberToDoubleConverter.java b/src/main/java/org/scijava/convert/NumberToDoubleConverter.java index 79ca2723b..302ea4d22 100644 --- a/src/main/java/org/scijava/convert/NumberToDoubleConverter.java +++ b/src/main/java/org/scijava/convert/NumberToDoubleConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/NumberToFloatConverter.java b/src/main/java/org/scijava/convert/NumberToFloatConverter.java index 8c036173a..afd969dbe 100644 --- a/src/main/java/org/scijava/convert/NumberToFloatConverter.java +++ b/src/main/java/org/scijava/convert/NumberToFloatConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/NumberToIntegerConverter.java b/src/main/java/org/scijava/convert/NumberToIntegerConverter.java index cc1aad5d7..e68c4cf29 100644 --- a/src/main/java/org/scijava/convert/NumberToIntegerConverter.java +++ b/src/main/java/org/scijava/convert/NumberToIntegerConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/NumberToLongConverter.java b/src/main/java/org/scijava/convert/NumberToLongConverter.java index 834388f9c..40c2c0bb8 100644 --- a/src/main/java/org/scijava/convert/NumberToLongConverter.java +++ b/src/main/java/org/scijava/convert/NumberToLongConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/NumberToNumberConverter.java b/src/main/java/org/scijava/convert/NumberToNumberConverter.java index edbe1aeda..40035dc1f 100644 --- a/src/main/java/org/scijava/convert/NumberToNumberConverter.java +++ b/src/main/java/org/scijava/convert/NumberToNumberConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,11 +43,11 @@ public abstract class NumberToNumberConverter T convert(final Object src, final Class dest) { - if (src == null || dest == null) throw new IllegalArgumentException( - "Null input"); + if (src == null || dest == null) // + throw new IllegalArgumentException("Null input"); if (!getInputType().isInstance(src)) { throw new IllegalArgumentException("Expected input of type " + - getInputType().getSimpleName() + ", but got " + + getInputType().getSimpleName() + ", but got " + // src.getClass().getSimpleName()); } if (Types.box(dest) != getOutputType()) { @@ -55,7 +55,9 @@ public T convert(final Object src, final Class dest) { "Expected output class of " + getOutputType().getSimpleName() + ", but got " + dest.getSimpleName()); } - return (T) convert((Number) src); + @SuppressWarnings("unchecked") + final T result = (T) convert((Number) src); + return result; } public abstract O convert(Number n); diff --git a/src/main/java/org/scijava/convert/NumberToShortConverter.java b/src/main/java/org/scijava/convert/NumberToShortConverter.java index 3c0666f2a..eda48e07f 100644 --- a/src/main/java/org/scijava/convert/NumberToShortConverter.java +++ b/src/main/java/org/scijava/convert/NumberToShortConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/PathToFileConverter.java b/src/main/java/org/scijava/convert/PathToFileConverter.java new file mode 100644 index 000000000..cc8aa967d --- /dev/null +++ b/src/main/java/org/scijava/convert/PathToFileConverter.java @@ -0,0 +1,61 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.convert; + +import java.io.File; +import java.nio.file.Path; + +import org.scijava.plugin.Plugin; + +/** + * A {@link Converter} used to convert {@link Path}s into {@link File}s. + * + * @author Gabriel Selzer + */ +@Plugin(type = Converter.class) +public class PathToFileConverter extends AbstractConverter { + + @SuppressWarnings("unchecked") + @Override + public T convert(final Object src, final Class dest) { + final Path p = (Path) src; + return (T) p.toFile(); + } + + @Override + public Class getOutputType() { + return File.class; + } + + @Override + public Class getInputType() { + return Path.class; + } +} diff --git a/src/main/java/org/scijava/convert/PrimitiveArrayUnwrapper.java b/src/main/java/org/scijava/convert/PrimitiveArrayUnwrapper.java index c9e1a0412..6292aee6d 100644 --- a/src/main/java/org/scijava/convert/PrimitiveArrayUnwrapper.java +++ b/src/main/java/org/scijava/convert/PrimitiveArrayUnwrapper.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,7 +41,7 @@ public abstract class PrimitiveArrayUnwrapper T convert(Object src, Class dest) { + public T convert(final Object src, final Class dest) { final W primitiveArray = (W) src; return (T) primitiveArray.getArray(); diff --git a/src/main/java/org/scijava/convert/PrimitiveArrayWrapper.java b/src/main/java/org/scijava/convert/PrimitiveArrayWrapper.java index 96fdd4211..f022900a8 100644 --- a/src/main/java/org/scijava/convert/PrimitiveArrayWrapper.java +++ b/src/main/java/org/scijava/convert/PrimitiveArrayWrapper.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/convert/StringToArrayConverter.java b/src/main/java/org/scijava/convert/StringToArrayConverter.java new file mode 100644 index 000000000..deeb58010 --- /dev/null +++ b/src/main/java/org/scijava/convert/StringToArrayConverter.java @@ -0,0 +1,170 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.convert; + +import java.lang.reflect.Array; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.scijava.Priority; +import org.scijava.parse.Item; +import org.scijava.parse.Items; +import org.scijava.parse.ParseService; +import org.scijava.parsington.Token; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.util.Types; + +/** + * A {@link Converter} that specializes in converting {@link String}s to + * n-dimensional arrays. This {@link Converter} can convert any array whose + * component types can be created from a {@link String}. By default, this + * {@link Converter} delimits the {@link String} based on commas. + * + * @author Gabriel Selzer + */ +@Plugin(type = Converter.class, priority = Priority.VERY_LOW) +public class StringToArrayConverter extends AbstractConverter { + + @Parameter(required = false) + private ConvertService convertService; + + @Parameter(required = false) + private ParseService parseService; + + @Override + public boolean canConvert(final Object src, final Type dest) { + return canConvert(src, Types.raw(dest)); + } + + @Override + public boolean canConvert(final Object src, final Class dest) { + if (convertService == null || parseService == null) return false; + + // First, ensure the base types conform + if (!canConvert(src.getClass(), dest)) return false; + // Then, ensure we can parse the string + try { + parseService.parse((String) src, false); + } + catch (final IllegalArgumentException e) { + return false; + } + return true; + } + + @Override + public boolean canConvert(final Class src, final Class dest) { + return src == String.class && dest.isArray(); + } + + @Override + public Object convert(final Object src, final Type dest) { + final Type componentType = Types.component(dest); + if (componentType == null) { + throw new IllegalArgumentException(dest + " is not an array type!"); + } + final List items = parse((String) src); + return convertToArray(items, Types.raw(componentType)); + } + + @Override + public T convert(final Object src, final Class dest) { + // NB: Invert functional flow from Converter interface: + // Converter: convert(Object, Type) calling convert(Object, Class) + // becomes: convert(Object, Class) calling convert(Object, Type) + final Type destType = dest; + @SuppressWarnings("unchecked") + T result = (T) convert(src, destType); + return result; + } + + @Override + public Class getOutputType() { + return Object.class; + } + + @Override + public Class getInputType() { + return String.class; + } + + // -- Helper methods -- + + /** + * Converts {@code src} into an array of component type {@code componentType}. + * + * @param tree the {@link String} to convert + * @param componentType the component type of the output array + * @return an array of {@code componentType} whose elements were created from + * {@code src} + */ + private Object convertToArray(final List tree, + final Class componentType) + { + // Create the array + final Object array = Array.newInstance(componentType, tree.size()); + // Set each element of the array + for (int i = 0; i < tree.size(); i++) { + Object element = tree.get(i); + final Object converted = convertService.convert(element, componentType); + Array.set(array, i, converted); + } + return array; + } + + /** Parses a string to a list, using the {@link ParseService}. */ + private List parse(final String s) { + try { + Items items = parseService.parse(s, false); + return (List) unwrap(items); + } + catch (final IllegalArgumentException e) { + return null; + } + } + + private Object unwrap(final Object o) { + if (o instanceof Collection) { + return ((Collection) o).stream() // + .map(item -> unwrap(item)) // + .collect(Collectors.toList()); + } + if (o instanceof Item) { + return unwrap(((Item) o).value()); + } + if (o instanceof Token) { + return ((Token) o).getToken(); + } + return o; + } +} diff --git a/src/main/java/org/scijava/convert/StringToNumberConverter.java b/src/main/java/org/scijava/convert/StringToNumberConverter.java index 6376a6a70..00a3f2640 100644 --- a/src/main/java/org/scijava/convert/StringToNumberConverter.java +++ b/src/main/java/org/scijava/convert/StringToNumberConverter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/AbstractDisplay.java b/src/main/java/org/scijava/display/AbstractDisplay.java index b3aa8cc47..e190f844c 100644 --- a/src/main/java/org/scijava/display/AbstractDisplay.java +++ b/src/main/java/org/scijava/display/AbstractDisplay.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/ActiveDisplayPreprocessor.java b/src/main/java/org/scijava/display/ActiveDisplayPreprocessor.java index b480f84d1..5997d66e8 100644 --- a/src/main/java/org/scijava/display/ActiveDisplayPreprocessor.java +++ b/src/main/java/org/scijava/display/ActiveDisplayPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/DefaultDisplay.java b/src/main/java/org/scijava/display/DefaultDisplay.java index 8813ccd1b..8b7755d44 100644 --- a/src/main/java/org/scijava/display/DefaultDisplay.java +++ b/src/main/java/org/scijava/display/DefaultDisplay.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/DefaultDisplayService.java b/src/main/java/org/scijava/display/DefaultDisplayService.java index 836f105f5..23a0c9c7f 100644 --- a/src/main/java/org/scijava/display/DefaultDisplayService.java +++ b/src/main/java/org/scijava/display/DefaultDisplayService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/DefaultTextDisplay.java b/src/main/java/org/scijava/display/DefaultTextDisplay.java index f9b0d3171..380507bdf 100644 --- a/src/main/java/org/scijava/display/DefaultTextDisplay.java +++ b/src/main/java/org/scijava/display/DefaultTextDisplay.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/Display.java b/src/main/java/org/scijava/display/Display.java index 0662c15f6..2221db211 100644 --- a/src/main/java/org/scijava/display/Display.java +++ b/src/main/java/org/scijava/display/Display.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/DisplayPostprocessor.java b/src/main/java/org/scijava/display/DisplayPostprocessor.java index 1f1db6ac0..7a6c54264 100644 --- a/src/main/java/org/scijava/display/DisplayPostprocessor.java +++ b/src/main/java/org/scijava/display/DisplayPostprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/DisplayService.java b/src/main/java/org/scijava/display/DisplayService.java index cc4a96b89..fcc13e0a0 100644 --- a/src/main/java/org/scijava/display/DisplayService.java +++ b/src/main/java/org/scijava/display/DisplayService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/Displayable.java b/src/main/java/org/scijava/display/Displayable.java index d079a4c96..67c0e26ee 100644 --- a/src/main/java/org/scijava/display/Displayable.java +++ b/src/main/java/org/scijava/display/Displayable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/TextDisplay.java b/src/main/java/org/scijava/display/TextDisplay.java index 63f58eb36..0ada43aad 100644 --- a/src/main/java/org/scijava/display/TextDisplay.java +++ b/src/main/java/org/scijava/display/TextDisplay.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/DisplayActivatedEvent.java b/src/main/java/org/scijava/display/event/DisplayActivatedEvent.java index 715a4a291..1fe30c96c 100644 --- a/src/main/java/org/scijava/display/event/DisplayActivatedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayActivatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/DisplayCreatedEvent.java b/src/main/java/org/scijava/display/event/DisplayCreatedEvent.java index 9cca17b84..347557f2f 100644 --- a/src/main/java/org/scijava/display/event/DisplayCreatedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayCreatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/DisplayDeletedEvent.java b/src/main/java/org/scijava/display/event/DisplayDeletedEvent.java index a558604a7..125ce25e3 100644 --- a/src/main/java/org/scijava/display/event/DisplayDeletedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayDeletedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/DisplayEvent.java b/src/main/java/org/scijava/display/event/DisplayEvent.java index 8bdd74598..99deab3ea 100644 --- a/src/main/java/org/scijava/display/event/DisplayEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/DisplayUpdatedEvent.java b/src/main/java/org/scijava/display/event/DisplayUpdatedEvent.java index ee62e8ad9..cbb1fc3ab 100644 --- a/src/main/java/org/scijava/display/event/DisplayUpdatedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayUpdatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/InputEvent.java b/src/main/java/org/scijava/display/event/input/InputEvent.java index bae65d081..4e278a185 100644 --- a/src/main/java/org/scijava/display/event/input/InputEvent.java +++ b/src/main/java/org/scijava/display/event/input/InputEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/KyEvent.java b/src/main/java/org/scijava/display/event/input/KyEvent.java index c045d99d2..058c986dc 100644 --- a/src/main/java/org/scijava/display/event/input/KyEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/KyPressedEvent.java b/src/main/java/org/scijava/display/event/input/KyPressedEvent.java index c8d73d8fb..e74dae63d 100644 --- a/src/main/java/org/scijava/display/event/input/KyPressedEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyPressedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/KyReleasedEvent.java b/src/main/java/org/scijava/display/event/input/KyReleasedEvent.java index ca7fdd18c..15659de2d 100644 --- a/src/main/java/org/scijava/display/event/input/KyReleasedEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyReleasedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/KyTypedEvent.java b/src/main/java/org/scijava/display/event/input/KyTypedEvent.java index f18264ef5..9f5d96c6e 100644 --- a/src/main/java/org/scijava/display/event/input/KyTypedEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyTypedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsButtonEvent.java b/src/main/java/org/scijava/display/event/input/MsButtonEvent.java index 51cf3adbb..09a91dabd 100644 --- a/src/main/java/org/scijava/display/event/input/MsButtonEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsButtonEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsClickedEvent.java b/src/main/java/org/scijava/display/event/input/MsClickedEvent.java index b4af7b6b8..f13524996 100644 --- a/src/main/java/org/scijava/display/event/input/MsClickedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsClickedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsDraggedEvent.java b/src/main/java/org/scijava/display/event/input/MsDraggedEvent.java index d02a8f9e9..f683dc4b9 100644 --- a/src/main/java/org/scijava/display/event/input/MsDraggedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsDraggedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsEnteredEvent.java b/src/main/java/org/scijava/display/event/input/MsEnteredEvent.java index 1fefc1f1c..310bcb444 100644 --- a/src/main/java/org/scijava/display/event/input/MsEnteredEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsEnteredEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsEvent.java b/src/main/java/org/scijava/display/event/input/MsEvent.java index e2288e32e..b370e1e79 100644 --- a/src/main/java/org/scijava/display/event/input/MsEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsExitedEvent.java b/src/main/java/org/scijava/display/event/input/MsExitedEvent.java index f47cda06f..921e674f1 100644 --- a/src/main/java/org/scijava/display/event/input/MsExitedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsExitedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsMovedEvent.java b/src/main/java/org/scijava/display/event/input/MsMovedEvent.java index c1c1030ce..658b1b904 100644 --- a/src/main/java/org/scijava/display/event/input/MsMovedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsMovedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsPressedEvent.java b/src/main/java/org/scijava/display/event/input/MsPressedEvent.java index cebaebae1..ea2593493 100644 --- a/src/main/java/org/scijava/display/event/input/MsPressedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsPressedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsReleasedEvent.java b/src/main/java/org/scijava/display/event/input/MsReleasedEvent.java index d9b39fe7d..61786d727 100644 --- a/src/main/java/org/scijava/display/event/input/MsReleasedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsReleasedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/input/MsWheelEvent.java b/src/main/java/org/scijava/display/event/input/MsWheelEvent.java index 008b66c11..32d92bd2f 100644 --- a/src/main/java/org/scijava/display/event/input/MsWheelEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsWheelEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinActivatedEvent.java b/src/main/java/org/scijava/display/event/window/WinActivatedEvent.java index 7220064e8..f8c81ec30 100644 --- a/src/main/java/org/scijava/display/event/window/WinActivatedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinActivatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinClosedEvent.java b/src/main/java/org/scijava/display/event/window/WinClosedEvent.java index e8e470175..24476f5aa 100644 --- a/src/main/java/org/scijava/display/event/window/WinClosedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinClosedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinClosingEvent.java b/src/main/java/org/scijava/display/event/window/WinClosingEvent.java index fa7b1bd79..ea6192681 100644 --- a/src/main/java/org/scijava/display/event/window/WinClosingEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinClosingEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinDeactivatedEvent.java b/src/main/java/org/scijava/display/event/window/WinDeactivatedEvent.java index 7d5e0b3e4..8a27cfdce 100644 --- a/src/main/java/org/scijava/display/event/window/WinDeactivatedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinDeactivatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinDeiconifiedEvent.java b/src/main/java/org/scijava/display/event/window/WinDeiconifiedEvent.java index 2af77304f..b6f620918 100644 --- a/src/main/java/org/scijava/display/event/window/WinDeiconifiedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinDeiconifiedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinEvent.java b/src/main/java/org/scijava/display/event/window/WinEvent.java index bfe00ebde..8190bfcde 100644 --- a/src/main/java/org/scijava/display/event/window/WinEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinIconifiedEvent.java b/src/main/java/org/scijava/display/event/window/WinIconifiedEvent.java index 7d50a608b..044182b2f 100644 --- a/src/main/java/org/scijava/display/event/window/WinIconifiedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinIconifiedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/display/event/window/WinOpenedEvent.java b/src/main/java/org/scijava/display/event/window/WinOpenedEvent.java index 3affb4051..4f10240f0 100644 --- a/src/main/java/org/scijava/display/event/window/WinOpenedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinOpenedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/download/DefaultDownloadService.java b/src/main/java/org/scijava/download/DefaultDownloadService.java index f87355f54..44c1b9aac 100644 --- a/src/main/java/org/scijava/download/DefaultDownloadService.java +++ b/src/main/java/org/scijava/download/DefaultDownloadService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/download/DiskLocationCache.java b/src/main/java/org/scijava/download/DiskLocationCache.java index 6442d9c27..ed576b4c4 100644 --- a/src/main/java/org/scijava/download/DiskLocationCache.java +++ b/src/main/java/org/scijava/download/DiskLocationCache.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/download/Download.java b/src/main/java/org/scijava/download/Download.java index 146c7eb96..f311000b4 100644 --- a/src/main/java/org/scijava/download/Download.java +++ b/src/main/java/org/scijava/download/Download.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/download/DownloadService.java b/src/main/java/org/scijava/download/DownloadService.java index 94ed5ce53..ecf576475 100644 --- a/src/main/java/org/scijava/download/DownloadService.java +++ b/src/main/java/org/scijava/download/DownloadService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/download/LocationCache.java b/src/main/java/org/scijava/download/LocationCache.java index 3f902f44e..3a5f7c031 100644 --- a/src/main/java/org/scijava/download/LocationCache.java +++ b/src/main/java/org/scijava/download/LocationCache.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/download/MultiWriteHandle.java b/src/main/java/org/scijava/download/MultiWriteHandle.java index eb9443133..4dd40b874 100644 --- a/src/main/java/org/scijava/download/MultiWriteHandle.java +++ b/src/main/java/org/scijava/download/MultiWriteHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/event/ContextCreatedEvent.java b/src/main/java/org/scijava/event/ContextCreatedEvent.java new file mode 100644 index 000000000..c279e9a7e --- /dev/null +++ b/src/main/java/org/scijava/event/ContextCreatedEvent.java @@ -0,0 +1,38 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.event; + +/** + * Event to be published immediately after a context has been fully created + * with all services initialized. + * + * @author Curtis Rueden + */ +public class ContextCreatedEvent extends SciJavaEvent { } diff --git a/src/main/java/org/scijava/event/ContextDisposingEvent.java b/src/main/java/org/scijava/event/ContextDisposingEvent.java index 77ef59e3d..570c0974c 100644 --- a/src/main/java/org/scijava/event/ContextDisposingEvent.java +++ b/src/main/java/org/scijava/event/ContextDisposingEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/event/DefaultEventBus.java b/src/main/java/org/scijava/event/DefaultEventBus.java index 7a7fd98bc..5587f6d59 100644 --- a/src/main/java/org/scijava/event/DefaultEventBus.java +++ b/src/main/java/org/scijava/event/DefaultEventBus.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,18 +34,17 @@ import java.util.Arrays; import java.util.List; -import org.bushe.swing.event.CleanupEvent; -import org.bushe.swing.event.ThreadSafeEventService; +import org.scijava.event.bushe.ThreadSafeEventService; import org.scijava.log.LogService; import org.scijava.service.Service; import org.scijava.thread.ThreadService; /** - * An {@link org.bushe.swing.event.EventService} implementation for SciJava. + * An {@code org.scijava.event.bushe.EventService} implementation for SciJava. *

* It is called "DefaultEventBus" rather than "DefaultEventService" to avoid a * name clash with {@link DefaultEventService}, which is not an - * {@link org.bushe.swing.event.EventService} but rather a SciJava + * {@code org.scijava.event.bushe.EventService} but rather a SciJava * {@link Service} implementation. *

* @@ -59,7 +58,7 @@ public class DefaultEventBus extends ThreadSafeEventService { public DefaultEventBus(final ThreadService threadService, final LogService log) { - super(200L, false, null, null, null); + super(200L, null, null, null); this.threadService = threadService; this.log = log; } @@ -112,37 +111,10 @@ public void publishLater(final String topicName, final Object eventObj) { getVetoEventListeners(topicName), null); } - // -- org.bushe.swing.event.EventService methods -- + // -- org.scijava.event.bushe.EventService methods -- @Override public void publish(final Object event) { - // HACK: Work around a deadlock problem caused by ThreadSafeEventService: - - // 1) The ThreadSafeEventService superclass has a special cleanup thread - // that takes care of cleaning up stale references. Every time it runs, it - // publishes some CleanupEvents using publish(Object) to announce that this - // is occurring. Normally, such publication delegates to - // publishNow, which calls ThreadService#invoke, which calls - // EventQueue.invokeAndWait, which queues the publication for execution on - // the EDT and then blocks until publication is complete. - - // 2) When the ThreadSafeEventService publishes the CleanupEvents, it does - // so inside a synchronized block that locks on a "listenerLock" object. - - // 3) Unfortunately, since the CleanupEvent publication is merely *queued*, - // any other pending operations on the EDT happen first. If one such - // operation meanwhile calls e.g. - // ThreadSafeEventService#getSubscribers(Class), it will deadlock because - // those getter methods are also synchronized on the listenerLock object. - - // Hence, our hack workaround is to instead use publishLater for the - // CleanupEvents, since no one really cares about them anyway. ;-) - - if (event instanceof CleanupEvent) { - publishLater(event); - return; - } - publishNow(event); } diff --git a/src/main/java/org/scijava/event/DefaultEventHistory.java b/src/main/java/org/scijava/event/DefaultEventHistory.java index 57cab6bdc..4b94b8bc3 100644 --- a/src/main/java/org/scijava/event/DefaultEventHistory.java +++ b/src/main/java/org/scijava/event/DefaultEventHistory.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/event/DefaultEventService.java b/src/main/java/org/scijava/event/DefaultEventService.java index d18b5c62e..3eca42db0 100644 --- a/src/main/java/org/scijava/event/DefaultEventService.java +++ b/src/main/java/org/scijava/event/DefaultEventService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,10 +40,9 @@ import java.util.Map; import java.util.WeakHashMap; -import org.bushe.swing.event.annotation.AbstractProxySubscriber; -import org.bushe.swing.event.annotation.BaseProxySubscriber; -import org.bushe.swing.event.annotation.ReferenceStrength; import org.scijava.Priority; +import org.scijava.event.bushe.AbstractProxySubscriber; +import org.scijava.event.bushe.ReferenceStrength; import org.scijava.log.LogService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; @@ -139,6 +138,11 @@ public List> subscribe(final Object o) { return subscribers; } + @Override + public void subscribe(final EventSubscriber subscriber) { + eventBus.subscribe(subscriber.getEventClass(), subscriber); + } + @Override public void unsubscribe(final Collection> subscribers) { for (final EventSubscriber subscriber : subscribers) { @@ -262,9 +266,10 @@ private synchronized void keepIt(final Object o, final ProxySubscriber subscr /** * Helper class used by {@link #subscribe(Object)}. *

- * Recapitulates some logic from {@link BaseProxySubscriber}, because that - * class implements {@link org.bushe.swing.event.EventSubscriber} as a raw - * type, which is incompatible with this class implementing SciJava's + * Recapitulates some logic from + * {@code org.scijava.event.bushe.BaseProxySubscriber}, because that class + * implements {@link org.scijava.event.bushe.EventSubscriber} as a raw type, + * which is incompatible with this class implementing SciJava's * {@link EventSubscriber} as a typed interface; it becomes impossible to * implement both {@code onEvent(Object)} and {@code onEvent(E)}. *

diff --git a/src/main/java/org/scijava/event/EventDetails.java b/src/main/java/org/scijava/event/EventDetails.java index b10ee4ff4..5e9344b24 100644 --- a/src/main/java/org/scijava/event/EventDetails.java +++ b/src/main/java/org/scijava/event/EventDetails.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/event/EventHandler.java b/src/main/java/org/scijava/event/EventHandler.java index ad94bda55..fa59a2a50 100644 --- a/src/main/java/org/scijava/event/EventHandler.java +++ b/src/main/java/org/scijava/event/EventHandler.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,15 +40,15 @@ * handling methods and annotating each with @{@link EventHandler}. *

* Note to developers: This annotation serves exactly the same purpose as - * EventBus's {@link org.bushe.swing.event.annotation.EventSubscriber} - * annotation, recapitulating a subset of the same functionality. We do this to - * avoid third party code depending directly on EventBus. That is, we do not - * wish to require SciJava developers to {@code import org.bushe.swing.event.*} - * or similar. In this way, EventBus is isolated as only a transitive dependency - * of downstream code, rather than a direct dependency. Unfortunately, because - * Java annotation interfaces cannot utilize inheritance, we have to - * recapitulate the functionality rather than extend it (as we are able to do - * with {@link EventSubscriber}). + * EventBus's {@code org.scijava.event.bushe.EventSubscriber} annotation, + * recapitulating a subset of the same functionality. We do this to avoid third + * party code depending directly on EventBus. That is, we do not wish to require + * SciJava developers to {@code import org.scijava.event.bushe.*} or similar. In + * this way, EventBus is isolated as only a transitive dependency of downstream + * code, rather than a direct dependency. Unfortunately, because Java annotation + * interfaces cannot utilize inheritance, we have to recapitulate the + * functionality rather than extend it (as we are able to do with + * {@link EventSubscriber}). *

* * @author Curtis Rueden diff --git a/src/main/java/org/scijava/event/EventHistory.java b/src/main/java/org/scijava/event/EventHistory.java index 3d0adfbad..7caaaf022 100644 --- a/src/main/java/org/scijava/event/EventHistory.java +++ b/src/main/java/org/scijava/event/EventHistory.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/event/EventHistoryListener.java b/src/main/java/org/scijava/event/EventHistoryListener.java index b06812dc0..30a305c83 100644 --- a/src/main/java/org/scijava/event/EventHistoryListener.java +++ b/src/main/java/org/scijava/event/EventHistoryListener.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/event/EventService.java b/src/main/java/org/scijava/event/EventService.java index 96d35aba1..1b0907f7a 100644 --- a/src/main/java/org/scijava/event/EventService.java +++ b/src/main/java/org/scijava/event/EventService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -125,6 +125,24 @@ public interface EventService extends SciJavaService { */ List> subscribe(Object o); + /** + * Subscribes the given {@link EventSubscriber} to its associated event class. + * Its {@link EventSubscriber#onEvent} method will be called whenever an event + * of the matching type is published. + *

+ * Important note: The event service does not keep a + * strong reference to the subscriber! If you use this method, you are also + * responsible for keeping a reference to the subscriber, or else it is likely + * to be garbage collected, and thus no longer respond to events as intended. + * One simple way to force a strong reference to exist is to add it to + * SciJava's {@link org.scijava.object.ObjectService} via + * {@link org.scijava.object.ObjectService#addObject}. + *

+ * + * @param subscriber the event subscriber to register + */ + void subscribe(EventSubscriber subscriber); + /** * Removes all the given subscribers; they will no longer be notified when * events are published. diff --git a/src/main/java/org/scijava/event/EventSubscriber.java b/src/main/java/org/scijava/event/EventSubscriber.java index 69725c846..9dcd25d94 100644 --- a/src/main/java/org/scijava/event/EventSubscriber.java +++ b/src/main/java/org/scijava/event/EventSubscriber.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,7 +44,7 @@ * @param Type of event for which to listen */ public interface EventSubscriber extends - org.bushe.swing.event.EventSubscriber + org.scijava.event.bushe.EventSubscriber { @Override diff --git a/src/main/java/org/scijava/event/SciJavaEvent.java b/src/main/java/org/scijava/event/SciJavaEvent.java index 4adf94671..4e51d775f 100644 --- a/src/main/java/org/scijava/event/SciJavaEvent.java +++ b/src/main/java/org/scijava/event/SciJavaEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/event/bushe/AbstractProxySubscriber.java b/src/main/java/org/scijava/event/bushe/AbstractProxySubscriber.java new file mode 100644 index 000000000..f0db8aac1 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/AbstractProxySubscriber.java @@ -0,0 +1,165 @@ +package org.scijava.event.bushe; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.InvocationTargetException; + +/** + * Common base class for EventService Proxies. + *

+ * Implementing Prioritized even when Priority is not used is always OK. The default + * value of 0 retains the FIFO order. + */ +public abstract class AbstractProxySubscriber implements ProxySubscriber, Prioritized { + private Object proxiedSubscriber; + private Method subscriptionMethod; + private ReferenceStrength referenceStrength; + private EventService eventService; + private int priority; + protected boolean veto; + + protected AbstractProxySubscriber(Object proxiedSubscriber, Method subscriptionMethod, + ReferenceStrength referenceStrength, EventService es, boolean veto) { + this(proxiedSubscriber, subscriptionMethod, referenceStrength, 0, es, veto); + } + + protected AbstractProxySubscriber(Object proxiedSubscriber, Method subscriptionMethod, + ReferenceStrength referenceStrength, int priority, EventService es, boolean veto) { + this.referenceStrength = referenceStrength; + this.priority = priority; + eventService = es; + this.veto = veto; + if (proxiedSubscriber == null) { + throw new IllegalArgumentException("The realSubscriber cannot be null when constructing a proxy subscriber."); + } + if (subscriptionMethod == null) { + throw new IllegalArgumentException("The subscriptionMethod cannot be null when constructing a proxy subscriber."); + } + Class returnType = subscriptionMethod.getReturnType(); + if (veto && returnType != Boolean.TYPE) { + throw new IllegalArgumentException("The subscriptionMethod must have the two parameters, the first one must be a String and the second a non-primitive (Object or derivative)."); + } + if (ReferenceStrength.WEAK.equals(referenceStrength)) { + this.proxiedSubscriber = new WeakReference(proxiedSubscriber); + } else { + this.proxiedSubscriber = proxiedSubscriber; + } + this.subscriptionMethod = subscriptionMethod; + } + + /** @return the object this proxy is subscribed on behalf of */ + public Object getProxiedSubscriber() { + if (proxiedSubscriber instanceof WeakReference) { + return ((WeakReference)proxiedSubscriber).get(); + } + return proxiedSubscriber; + } + + /** @return the subscriptionMethod passed in the constructor */ + public Method getSubscriptionMethod() { + return subscriptionMethod; + } + + /** @return the EventService passed in the constructor */ + public EventService getEventService() { + return eventService; + } + + /** @return the ReferenceStrength passed in the constructor */ + public ReferenceStrength getReferenceStrength() { + return referenceStrength; + } + + /** + * @return the priority, no effect if priority is 0 (the default value) + */ + public int getPriority() { + return priority; + } + + /** + * Called by EventServices to inform the proxy that it is unsubscribed. + * The ProxySubscriber should perform any necessary cleanup. + *

+ * Overriding classes must call super.proxyUnsubscribed() or risk + * things not being cleanup up properly. + */ + public void proxyUnsubscribed() { + proxiedSubscriber = null; + } + + @Override + public final int hashCode() { + throw new RuntimeException("Proxy subscribers are not allowed in Hash " + + "Maps, since the underlying values use Weak References that" + + "may disappear, the calculations may not be the same in" + + "successive calls as required by hashCode."); + } + + protected boolean retryReflectiveCallUsingAccessibleObject(Object[] args, Method subscriptionMethod, Object obj, + IllegalAccessException e, String message) { + boolean accessibleTriedAndFailed = false; + if (subscriptionMethod != null) { + AccessibleObject[] accessibleMethod = {subscriptionMethod}; + try { + AccessibleObject.setAccessible(accessibleMethod, true); + Object returnValue = subscriptionMethod.invoke(obj, args); + return Boolean.valueOf(returnValue+""); + } catch (SecurityException ex) { + accessibleTriedAndFailed = true; + } catch (InvocationTargetException e1) { + throw new RuntimeException(message, e); + } catch (IllegalAccessException e1) { + throw new RuntimeException(message, e); + } + } + if (accessibleTriedAndFailed) { + message = message + ". An attempt was made to make the method accessible, but the SecurityManager denied the attempt."; + } + throw new RuntimeException(message, e); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AbstractProxySubscriber) { + AbstractProxySubscriber bps = (AbstractProxySubscriber) obj; + if (referenceStrength != bps.referenceStrength) { + return false; + } + if (subscriptionMethod != bps.subscriptionMethod) { + return false; + } + if (ReferenceStrength.WEAK == referenceStrength) { + if (((WeakReference)proxiedSubscriber).get() != ((WeakReference)bps.proxiedSubscriber).get()) { + return false; + } + } else { + if (proxiedSubscriber != bps.proxiedSubscriber) { + return false; + } + } + if (veto != bps.veto) { + return false; + } + if (eventService != bps.eventService) { + return false; + } + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return "AbstractProxySubscriber{" + + "realSubscriber=" + (proxiedSubscriber instanceof WeakReference? + ((WeakReference)proxiedSubscriber).get():proxiedSubscriber) + + ", subscriptionMethod=" + subscriptionMethod + + ", veto=" + veto + + ", referenceStrength=" + referenceStrength + + ", eventService=" + eventService + + '}'; + } +} diff --git a/src/main/java/org/scijava/event/bushe/EventService.java b/src/main/java/org/scijava/event/bushe/EventService.java new file mode 100644 index 000000000..c2d41e9bb --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/EventService.java @@ -0,0 +1,988 @@ +/** + * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com + * + * Licensed 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.scijava.event.bushe; + +import java.util.List; +import java.util.regex.Pattern; +import java.lang.reflect.Type; + +/** + * The core interface. An EventService provides publish/subscribe services to a single JVM using Class-based and + * String-based (i.e. "topic") publications and subscriptions. + *

+ * In class-based pub/sub, {@link EventSubscriber}s subscribe to a type on an {@link EventService}, such + * as the {@link org.scijava.event.bushe.EventBus}, by providing a class, interface or generic type. The EventService + * notifies subscribers when objects are published on the EventService with a matching type. Full class semantics are + * respected. That is, if a subscriber subscribes to a class, the subscriber is notified if an object of + * that class is publish or if an object of a subclass of that class is published. Likewise if a subscriber subscribes + * to an interface, it will be notified if any object that implements that interface is published. Subscribers can + * subscribe "exactly" using {@link #subscribeExactly(Class, EventSubscriber)} so that they are notified only if an + * object of the exact class is published (and will not be notified if subclasses are published, since this would not + * be "exact") + *

+ *

+ * In topic-based pub/sub, an object "payload" is published on a topic name (String). {@link EventTopicSubscriber}s subscribe + * to either the exact name of the topic or they may subscribe using a Regular Expression that is used to match topic + * names. + *

+ *

+ * See the overview for an general introduction + * and package documentation for usage details and examples. + *

+ *

+ * A single subscriber cannot subscribe more than once to an event or topic name. EventService implementations should + * handle double-subscription requests by returning false on subscribe(). A single EventSubscriber can subscribe to more + * than one event class, and a single EventTopicSubscriber can subscribe to more than one topic name or pattern. A + * single object may implement both EventSubscriber and EventTopicSubscriber interfaces. Subscribers are guaranteed to + * only be called for the classes and/or topic names they subscribe to. If a subscriber subscribes to a topic and to a + * regular expression that matches the topic name, this is considered two different subscriptions and the subscriber + * will be called twice for the publication on the topic. Similarly, if a subscriber subscribes to a class and its + * subclasses using subscribe() and again to a class of the same type using subscribeExactly(), this is considered two + * different subscriptions and the subscriber will be called twice for the publication for a single event of the exact + * type. + *

+ *

+ * By default the EventService only holds WeakReferences to subscribers. If a subscriber has no references to it, then + * it can be garbage collected. This avoids memory leaks in exchange for the risk of accidentally adding a listener and + * have it disappear unexpectedly. If you want to subscribe a subscriber that will have no other reference to it, then + * use one of the subscribeStrongly() methods, which will prevent garbage collection. + *

+ *

+ * Unless garbage collected, EventSubscribers will remain subscribed until they are passed to one of the unsubscribe() + * methods with the event class or topic name to which there are subscribed. + *

+ *

+ * Subscribers are called in the order in which they are subscribed by default (FIFO), unless subscribers implement + * {@link Prioritized}. Those subscribers that implement Prioritized and return a negative priority are moved to the + * front of the list (the more negative, the more to the front). Those subscribers that implement Prioritized and return + * a positive priority are moved to the end of the list (the more positive, the more to the back). The FIFO guarantee + * is only valid for the same subscribe() call. That is, the order of two subscribers, one to List.class and the other + * to ArrayList.class is not guaranteed to be in the order of subscription when an ArrayList is published. The same is + * true for topic subscribers when using RegEx expressions - when "Foo" is published, the order of subscribers that are + * subscribed to "Foo", "Fo*" and "F*" are not guaranteed, though the second "Fo*" subscriber will never be called + * before the first "Fo*" subscriber (ditto List and ArrayList). Prioritized subscribers are always guaranteed to be in + * the order of priority, no matter the call or the resulting mix of subscribers. All ordering rules apply to all + * types subscribers: class, topic, pattern, veto, etc. For Swing users, note that FIFO is + * the opposite of Swing, where event listeners are called in the reverse order of when they were subscribed (FILO). + *

+ *

+ * Publication on a class or topic name can be vetoed by a {@link VetoEventListener}. All VetoEventListeners are checked + * before any EventSubscribers or EventTopicSubscribers are called. This is unlike the JavaBean's + * VetoPropertyEventListener which can leave side effects and half-propogated events. VetoEventListeners are subscribed + * in the same manner as EventSubscribers and EventTopicSubscribers. + *

+ *

+ * The state of a published event can be tracked if an event or a topic's payload object implements the + * {@link org.scijava.event.bushe.PublicationStatus} interface. EventServices are required to set such objects' + * {@link org.scijava.event.bushe.PublicationStatus} at the appropriate times during publication. + *

+*

+ * This simple example prints "Hello World" + *

+ * EventService eventService = new ThreadSafeEventService();
+ * //Create a subscriber
+ * EventTopicSubscriber subscriber = new EventTopicSubscriber() {
+ *    public void onEvent(String topic, Object event) {
+ *        System.out.println(topic+" "+event);
+ *    }
+ * });
+ * eventService.subscribe("Hello", subscriber);
+ * eventService.publish("Hello", "World");
+ * System.out.println(subscriber + " Since the reference is used after it is subscribed, it doesn't get garbage collected, this is not necessary if you use subscribeStrongly()");
+ * 
+ *

+ *

+ * Events and/or topic data can be cached, but are not by default. To cache events or topic data, call + * {@link #setDefaultCacheSizePerClassOrTopic(int)}, {@link #setCacheSizeForEventClass(Class, int)}, or + * {@link #setCacheSizeForTopic(String, int)}, {@link #setCacheSizeForTopic(Pattern, int)}. Retrieve cached values + * with {@link #getLastEvent(Class)}, {@link #getLastTopicData(String)}, {@link #getCachedEvents(Class)}, or + * {@link #getCachedTopicData(String)}. Using caching while subscribing is most likely to make sense only if you + * subscribe and publish on the same thread (so caching is very useful for Swing applications since both happen on + * the EDT in a single-threaded manner). In multithreaded applications, you never know if your subscriber has handled + * an event while it was being subscribed (before the subscribe() method returned) that is newer or older than the + * retrieved cached value (taken before or after subscribe() respectively). + *

+ *

+ * There is nothing special about the term "Event," this could just as easily be called a "Message" Service, this term + * is already taken by the JMS, which is similar, but is used across processes and networks. + *

+ * + * @author Michael Bushe michael@bushe.com + * @see {@link ThreadSafeEventService} for the default implementation + */ +interface EventService { + + /** + * Publishes an object so that subscribers will be notified if they subscribed to the object's class, one of its + * subclasses, or to one of the interfaces it implements. + * + * @param event the object to publish + */ + public void publish(Object event); + + /** + * Use this method to publish generified objects to subscribers of Types, i.e. subscribers that use + * {@link #subscribe(Type, EventSubscriber)}, and to publish to subscribers of the non-generic type. + *

+ * Due to generic type erasure, the type must be supplied by the caller. You can get a declared object's + * type by using the {@link org.scijava.event.bushe.TypeReference} class. For Example: + *

+ *
+    * TypeReference<List<Trade>> subscribingTypeReference = new TypeReference<List<Trade>>(){};
+    * EventBus.subscribe(subscribingTypeReference.getType(), mySubscriber);
+    * EventBus.subscribe(List.class, thisSubscriberWillGetCalledToo);
+    * ...
+    * //Likely in some other class
+    * TypeReference<List<Trade>> publishingTypeReference = new TypeReference<List<Trade>>(){};
+    * List<Trade> trades = new ArrayList<Trade>();
+    * EventBus.publish(publishingTypeReference.getType(), trades);
+    * trades.add(trade);
+    * EventBus.publish(publishingTypeReference.getType(), trades);
+    * 
+ * @param genericType the generified type of the published object. + * @param event The event that occurred + */ + public void publish(Type genericType, Object event); + + /** + * Publishes an object on a topic name so that all subscribers to that name or a Regular Expression that matches + * the topic name will be notified. + * + * @param topic The name of the topic subscribed to + * @param o the object to publish + */ + public void publish(String topic, Object o); + + /** + * Subscribes an EventSubscriber to the publication of objects matching a type. Only a WeakReference to + * the subscriber is held by the EventService. + *

+ * Subscribing to a class means the subscriber will be called when objects of that class are published, when + * objects of subclasses of the class are published, when objects implementing any of the interfaces of the + * class are published, or when generic types are published with the class' raw type. + *

+ *

+ * Subscription is weak by default to avoid having to call unsubscribe(), and to avoid the memory leaks that would + * occur if unsubscribe was not called. The service will respect the WeakReference semantics. In other words, if + * the subscriber has not been garbage collected, then onEvent(Object) will be called normally. If the hard + * reference has been garbage collected, the service will unsubscribe it's WeakReference. + *

+ *

+ * It's allowable to call unsubscribe() with the same EventSubscriber hard reference to stop a subscription + * immediately. + *

+ *

+ * The service will create the WeakReference on behalf of the caller. + *

+ * + * @param eventClass the class of published objects to subscriber listen to + * @param subscriber The subscriber that will accept the events of the event class when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribe(Class eventClass, EventSubscriber subscriber); + + /** + * Subscribe an EventSubscriber to publication of generic Types. + * Subscribers will only be notified for publications using {@link #publish(java.lang.reflect.Type, Object)}. + *

+ * Due to generic type erasure, the type must be supplied by the publisher. You can get a declared object's + * type by using the {@link org.scijava.event.bushe.TypeReference} class. For Example: + *

+ *
+   * TypeReference<List<Trade>> subscribingTypeReference = new TypeReference<List<Trade>>(){};
+   * EventBus.subscribe(subscribingTypeReference.getType(), mySubscriber);
+   * EventBus.subscribe(List.class, thisSubscriberWillGetCalledToo);
+   * ...
+   * //Likely in some other class
+   * TypeReference<List<Trade>> publishingTypeReference = new TypeReference<List<Trade>>(){};
+   * List<Trade> trades = new ArrayList<Trade>();
+   * EventBus.publish(publishingTypeReference.getType(), trades);
+   * trades.add(trade);
+   * EventBus.publish(publishingTypeReference.getType(), trades);
+   * 
+ * @param type the generic type to subscribe to + * @param subscriber the subscriber to the type + * @return true if a new subscription is made, false if it already existed + */ + public boolean subscribe(Type type, EventSubscriber subscriber); + + /** + * Subscribes an EventSubscriber to the publication of objects exactly matching a type. Only a WeakReference + * to the subscriber is held by the EventService. + *

+ * Subscription is weak by default to avoid having to call unsubscribe(), and to avoid the memory leaks that would + * occur if unsubscribe was not called. The service will respect the WeakReference semantics. In other words, if + * the subscriber has not been garbage collected, then the onEvent will be called normally. If the hard reference + * has been garbage collected, the service will unsubscribe it's WeakReference. + *

+ *

+ * It's allowable to call unsubscribe() with the same EventSubscriber hard reference to stop a subscription + * immediately. + *

+ *

+ * The service will create the WeakReference on behalf of the caller. + *

+ * + * @param eventClass the class of published objects to listen to + * @param subscriber The subscriber that will accept the events when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribeExactly(Class eventClass, EventSubscriber subscriber); + + /** + * Subscribes an EventTopicSubscriber to the publication of a topic name. Only a WeakReference + * to the subscriber is held by the EventService. + *

+ * Subscription is weak by default to avoid having to call unsubscribe(), and to avoid the memory leaks that would + * occur if unsubscribe was not called. The service will respect the WeakReference semantics. In other words, if + * the subscriber has not been garbage collected, then the onEvent will be called normally. If the hard reference + * has been garbage collected, the service will unsubscribe it's WeakReference. + *

+ *

+ * It's allowable to call unsubscribe() with the same EventSubscriber hard reference to stop a subscription + * immediately. + *

+ * + * @param topic the name of the topic listened to + * @param subscriber The topic subscriber that will accept the events when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribe(String topic, EventTopicSubscriber subscriber); + + /** + * Subscribes an EventSubscriber to the publication of all the topic names that match a RegEx Pattern. Only a + * WeakReference to the subscriber is held by the EventService. + *

+ * Subscription is weak by default to avoid having to call unsubscribe(), and to avoid the memory leaks that would + * occur if unsubscribe was not called. The service will respect the WeakReference semantics. In other words, if + * the subscriber has not been garbage collected, then the onEvent will be called normally. If the hard reference + * has been garbage collected, the service will unsubscribe it's WeakReference. + *

+ *

+ * It's allowable to call unsubscribe() with the same EventSubscriber hard reference to stop a subscription + * immediately. + *

+ * + * @param topicPattern pattern that matches to the name of the topic published to + * @param subscriber The topic subscriber that will accept the events when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribe(Pattern topicPattern, EventTopicSubscriber subscriber); + + /** + * Subscribes an EventSubscriber to the publication of objects matching a type. + *

+ * The semantics are the same as {@link #subscribe(Class, EventSubscriber)}, except that the EventService holds + * a regularly reference, not a WeakReference. + *

+ *

+ * The subscriber will remain subscribed until {@link #unsubscribe(Class,EventSubscriber)} is called. + *

+ * + * @param eventClass the class of published objects to listen to + * @param subscriber The subscriber that will accept the events when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribeStrongly(Class eventClass, EventSubscriber subscriber); + + /** + * Subscribes an EventSubscriber to the publication of objects matching a type exactly. + *

+ * The semantics are the same as {@link #subscribeExactly(Class, EventSubscriber)}, except that the EventService + * holds a regularly reference, not a WeakReference. + *

+ *

+ * The subscriber will remain subscribed until {@link #unsubscribe(Class,EventSubscriber)} is called. + *

+ * + * @param eventClass the class of published objects to listen to + * @param subscriber The subscriber that will accept the events when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribeExactlyStrongly(Class eventClass, EventSubscriber subscriber); + + /** + * Subscribes a subscriber to an event topic name. + *

+ * The semantics are the same as {@link #subscribe(String, EventTopicSubscriber)}, except that the EventService + * holds a regularly reference, not a WeakReference. + *

+ *

+ * The subscriber will remain subscribed until {@link #unsubscribe(String,EventTopicSubscriber)} is called. + *

+ * + * @param topic the name of the topic listened to + * @param subscriber The topic subscriber that will accept the events when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribeStrongly(String topic, EventTopicSubscriber subscriber); + + /** + * Subscribes a subscriber to all the event topic names that match a RegEx expression. + *

+ * The semantics are the same as {@link #subscribe(java.util.regex.Pattern, EventTopicSubscriber)}, except that the + * EventService holds a regularly reference, not a WeakReference. + *

+ *

+ * The subscriber will remain subscribed until {@link #unsubscribe(String,EventTopicSubscriber)} is called. + *

+ * + * @param topicPattern the name of the topic listened to + * @param subscriber The topic subscriber that will accept the events when published. + * + * @return true if the subscriber was subscribed successfully, false otherwise + */ + public boolean subscribeStrongly(Pattern topicPattern, EventTopicSubscriber subscriber); + + /** + * Stop the subscription for a subscriber that is subscribed to a class. + * + * @param eventClass the class of published objects to listen to + * @param subscriber The subscriber that is subscribed to the event. The same reference as the one subscribed. + * + * @return true if the subscriber was subscribed to the event, false if it wasn't + */ + public boolean unsubscribe(Class eventClass, EventSubscriber subscriber); + + /** + * Stop the subscription for a subscriber that is subscribed to an exact class. + * + * @param eventClass the class of published objects to listen to + * @param subscriber The subscriber that is subscribed to the event. The same reference as the one subscribed. + * + * @return true if the subscriber was subscribed to the event, false if it wasn't + */ + public boolean unsubscribeExactly(Class eventClass, EventSubscriber subscriber); + + /** + * Stop the subscription for a subscriber that is subscribed to an event topic. + * + * @param topic the topic listened to + * @param subscriber The subscriber that is subscribed to the topic. The same reference as the one subscribed. + * + * @return true if the subscriber was subscribed to the event, false if it wasn't + */ + public boolean unsubscribe(String topic, EventTopicSubscriber subscriber); + + /** + * Stop the subscription for a subscriber that is subscribed to event topics via a Pattern. + * + * @param topicPattern the regex expression matching topics listened to + * @param subscriber The subscriber that is subscribed to the topic. The same reference as the one subscribed. + * + * @return true if the subscriber was subscribed to the event, false if it wasn't + */ + public boolean unsubscribe(Pattern topicPattern, EventTopicSubscriber subscriber); + + /** + * Subscribes a VetoEventListener to publication of event matching a class. Only a WeakReference to the + * VetoEventListener is held by the EventService. + *

+ * Use this method to avoid having to call unsubscribe(), though with care since garbage collection semantics is + * indeterminate. The service will respect the WeakReference semantics. In other words, if the vetoListener has not + * been garbage collected, then the onEvent will be called normally. If the hard reference has been garbage + * collected, the service will unsubscribe it's WeakReference. + *

+ *

+ * It's allowable to call unsubscribe() with the same VetoEventListener hard reference to stop a subscription + * immediately. + *

+ *

+ * The service will create the WeakReference on behalf of the caller. + *

+ * + * @param eventClass the class of published objects that can be vetoed + * @param vetoListener The VetoEventListener that can determine whether an event is published. + * + * @return true if the VetoEventListener was subscribed successfully, false otherwise + */ + public boolean subscribeVetoListener(Class eventClass, VetoEventListener vetoListener); + + /** + * Subscribes a VetoEventListener to publication of an exact event class. Only a WeakReference to the + * VetoEventListener is held by the EventService. + *

+ * Use this method to avoid having to call unsubscribe(), though with care since garbage collection semantics is + * indeterminate. The service will respect the WeakReference semantics. In other words, if the vetoListener has not + * been garbage collected, then the onEvent will be called normally. If the hard reference has been garbage + * collected, the service will unsubscribe it's WeakReference. + *

+ *

+ * It's allowable to call unsubscribe() with the same VetoEventListener hard reference to stop a subscription + * immediately. + *

+ *

+ * The service will create the WeakReference on behalf of the caller. + *

+ * + * @param eventClass the class of published objects that can be vetoed + * @param vetoListener The vetoListener that can determine whether an event is published. + * + * @return true if the vetoListener was subscribed successfully, false otherwise + */ + public boolean subscribeVetoListenerExactly(Class eventClass, VetoEventListener vetoListener); + + /** + * Subscribes a VetoTopicEventListener to a topic name. Only a WeakReference to the + * VetoEventListener is held by the EventService. + * + * @param topic the name of the topic listened to + * @param vetoListener The vetoListener that can determine whether an event is published. + * + * @return true if the vetoListener was subscribed successfully, false otherwise + */ + public boolean subscribeVetoListener(String topic, VetoTopicEventListener vetoListener); + + /** + * Subscribes an VetoTopicEventListener to all the topic names that match the RegEx Pattern. Only a + * WeakReference to the VetoEventListener is held by the EventService. + * + * @param topicPattern the RegEx pattern to match topics with + * @param vetoListener The vetoListener that can determine whether an event is published. + * + * @return true if the vetoListener was subscribed successfully, false otherwise + */ + public boolean subscribeVetoListener(Pattern topicPattern, VetoTopicEventListener vetoListener); + + /** + * Subscribes a VetoEventListener for an event class and its subclasses. Only a WeakReference to the + * VetoEventListener is held by the EventService. + *

+ * The VetoEventListener will remain subscribed until {@link #unsubscribeVetoListener(Class,VetoEventListener)} is + * called. + *

+ * + * @param eventClass the class of published objects to listen to + * @param vetoListener The vetoListener that will accept the events when published. + * + * @return true if the vetoListener was subscribed successfully, false otherwise + */ + public boolean subscribeVetoListenerStrongly(Class eventClass, VetoEventListener vetoListener); + + /** + * Subscribes a VetoEventListener for an event class (but not its subclasses). + *

+ * The VetoEventListener will remain subscribed until {@link #unsubscribeVetoListener(Class,VetoEventListener)} is + * called. + *

+ * + * @param eventClass the class of published objects to listen to + * @param vetoListener The vetoListener that will accept the events when published. + * + * @return true if the vetoListener was subscribed successfully, false otherwise + */ + public boolean subscribeVetoListenerExactlyStrongly(Class eventClass, VetoEventListener vetoListener); + + /** + * Subscribes a VetoEventListener to a topic name. + *

+ * The VetoEventListener will remain subscribed until {@link #unsubscribeVetoListener(String,VetoTopicEventListener)} is + * called. + *

+ * + * @param topic the name of the topic listened to + * @param vetoListener The topic vetoListener that will accept or reject publication. + * + * @return true if the vetoListener was subscribed successfully, false otherwise + * + * @see #subscribeVetoListenerStrongly(Class,VetoEventListener) + */ + public boolean subscribeVetoListenerStrongly(String topic, VetoTopicEventListener vetoListener); + + /** + * Subscribes a VetoTopicEventListener to a set of topics that match a RegEx expression. + *

+ * The VetoEventListener will remain subscribed until {@link #unsubscribeVetoListener(Pattern,VetoTopicEventListener)} is + * called. + *

+ * + * @param topicPattern the RegEx pattern that matches the name of the topics listened to + * @param vetoListener The topic vetoListener that will accept or reject publication. + * + * @return true if the vetoListener was subscribed successfully, false otherwise + * + * @see #subscribeVetoListenerStrongly(Pattern,VetoTopicEventListener) + */ + public boolean subscribeVetoListenerStrongly(Pattern topicPattern, VetoTopicEventListener vetoListener); + + /** + * Stop the subscription for a vetoListener that is subscribed to an event class and its subclasses. + * + * @param eventClass the class of published objects that can be vetoed + * @param vetoListener The vetoListener that will accept or reject publication of an event. + * + * @return true if the vetoListener was subscribed to the event, false if it wasn't + */ + public boolean unsubscribeVetoListener(Class eventClass, VetoEventListener vetoListener); + + /** + * Stop the subscription for a vetoListener that is subscribed to an event class (but not its subclasses). + * + * @param eventClass the class of published objects that can be vetoed + * @param vetoListener The vetoListener that will accept or reject publication of an event. + * + * @return true if the vetoListener was subscribed to the event, false if it wasn't + */ + public boolean unsubscribeVetoListenerExactly(Class eventClass, VetoEventListener vetoListener); + + /** + * Stop the subscription for a VetoTopicEventListener that is subscribed to an event topic name. + * + * @param topic the name of the topic that is listened to + * @param vetoListener The vetoListener that can determine whether an event is published on that topic + * + * @return true if the vetoListener was subscribed to the topic, false if it wasn't + */ + public boolean unsubscribeVetoListener(String topic, VetoTopicEventListener vetoListener); + + /** + * Stop the subscription for a VetoTopicEventListener that is subscribed to an event topic RegEx pattern. + * + * @param topicPattern the RegEx pattern matching the name of the topics listened to + * @param vetoListener The vetoListener that can determine whether an event is published on that topic + * + * @return true if the vetoListener was subscribed to the topicPattern, false if it wasn't + */ + public boolean unsubscribeVetoListener(Pattern topicPattern, VetoTopicEventListener vetoListener); + + /** + * Union of getSubscribersToClass(Class) and getSubscribersToExactClass(Class) + * + * @param eventClass the eventClass of interest + * + * @return the subscribers that will be called when an event of eventClass is published, this includes those + * subscribed that match by exact class and those that match to a class and its supertypes + */ + public List getSubscribers(Class eventClass); + + /** + * Gets subscribers that subscribed with the given a class, but not those subscribed exactly to the class. + * @param eventClass the eventClass of interest + * + * @return the subscribers that are subscribed to match to a class and its supertypes, but not those subscribed by + * exact class + */ + public List getSubscribersToClass(Class eventClass); + + /** + * Gets subscribers that are subscribed exactly to a class, but not those subscribed non-exactly to a class. + * @param eventClass the eventClass of interest + * + * @return the subscribers that are subscribed by exact class but not those subscribed to match to a class and its + * supertypes + */ + public List getSubscribersToExactClass(Class eventClass); + + /** + * Gets the subscribers that subscribed to a generic type. + * + * @param type the type of interest + * + * @return the subscribers that will be called when an event of eventClass is published, this includes those + * subscribed that match by exact class and those that match to a class and its supertypes + */ + public List getSubscribers(Type type); + + /** + * Union of getSubscribersByPattern(String) and geSubscribersToTopic(String) + * + * @param topic the topic of interest + * + * @return the subscribers that will be called when an event is published on the topic. This includes subscribers + * subscribed to match the exact topic name and those subscribed by a RegEx Pattern that matches the topic + * name. + */ + public List getSubscribers(String topic); + + /** + * Get the subscribers that subscribed to a topic. + * @param topic the topic of interest + * + * @return the subscribers that subscribed to the exact topic name. + */ + public List getSubscribersToTopic(String topic); + + /** + * Gets the subscribers that subscribed to a regular expression. + * @param pattern the RegEx pattern that was subscribed to + * + * @return the subscribers that were subscribed to this pattern. + */ + public List getSubscribers(Pattern pattern); + + /** + * Gets the subscribers that subscribed with a Pattern that matches the given topic. + * @param topic a topic to match Patterns against + * + * @return the subscribers that subscribed by a RegEx Pattern that matches the topic name. + */ + public List getSubscribersByPattern(String topic); + + /** + * Gets veto subscribers that subscribed to a given class. + * @param eventClass the eventClass of interest + * + * @return the veto subscribers that will be called when an event of eventClass or its subclasses is published. + */ + public List getVetoSubscribers(Class eventClass); + + /** + * Get veto subscribers that subscribed to a given class exactly. + * @param eventClass the eventClass of interest + * + * @return the veto subscribers that will be called when an event of eventClass (but not its subclasses) is + * published. + */ + public List getVetoSubscribersToExactClass(Class eventClass); + + /** + * Gets the veto subscribers that subscribed to a class. + * @param eventClass the eventClass of interest + * + * @return the veto subscribers that are subscribed to the eventClass and its subclasses + */ + public List getVetoSubscribersToClass(Class eventClass); + + /** + * Union of {@link #getVetoSubscribersToTopic(String)} and {@link #getVetoSubscribersByPattern(String)} + * Misnamed method, should be called {@link #getVetoSubscribers(String)}. Will be deprecated in 1.5. + * + * @param topicOrPattern the topic or pattern of interest + * + * @return the veto subscribers that will be called when an event is published on the topic. + */ + public List getVetoEventListeners(String topicOrPattern); + + /** + * Gets the veto subscribers that subscribed to a topic. + * @param topic the topic of interest + * + * @return the veto subscribers that will be called when an event is published on the topic. + */ + public List getVetoSubscribersToTopic(String topic); + + /** + * Gets the veto subscribers that subscribed to a regular expression. + * @param pattern the RegEx pattern for the topic of interest + * + * @return the veto subscribers that were subscribed to this pattern. + */ + public List getVetoSubscribers(Pattern pattern); + + /** + * Gets the veto subscribers that are subscribed by pattern that match the topic. + * @param topic the topic to match the pattern string subscribed to + * + * @return the veto subscribers that subscribed by pattern that will be called when an event is published on the topic. + */ + public List getVetoSubscribersByPattern(String topic); + + /** + * Misnamed method for backwards compatibility. + * Duplicate of {@link #getVetoSubscribersToTopic(String)}. + * Out of sync with {@link #getSubscribers(String)}. + * @param topic the topic exactly subscribed to + * + * @return the veto subscribers that are subscribed to the topic. + * @deprecated use getVetoSubscribersToTopic instead for direct replacement, + * or use getVetoEventListeners to get topic and pattern matchers. + * In EventBus 2.0 this name will replace getVetoEventListeners() + * and have it's union functionality + */ + public List getVetoSubscribers(String topic); + + /** Clears all current subscribers and veto subscribers */ + public void clearAllSubscribers(); + + /** + * Sets the default cache size for each kind of event, default is 0 (no caching). + *

+ * If this value is set to a positive number, then when an event is published, the EventService caches the event or + * topic payload data for later retrieval. This allows subscribers to find out what has most recently happened + * before they subscribed. The cached event(s) are returned from #getLastEvent(Class), #getLastTopicData(String), + * #getCachedEvents(Class), or #getCachedTopicData(String) + *

+ *

+ * The default can be overridden on a by-event-class or by-topic basis. + *

+ * + * @param defaultCacheSizePerClassOrTopic the cache size per event + */ + public void setDefaultCacheSizePerClassOrTopic(int defaultCacheSizePerClassOrTopic); + + /** + * The default number of events or payloads kept per event class or topic + * @return the default number of event payloads kept per event class or topic + */ + public int getDefaultCacheSizePerClassOrTopic(); + + /** + * Set the number of events cached for a particular class of event. By default, no events are cached. + *

+ * This overrides any setting for the DefaultCacheSizePerClassOrTopic. + *

+ *

+ * Class hierarchy semantics are respected. That is, if there are three events, A, X and Y, and X and Y are both + * derived from A, then setting the cache size for A applies the cache size for all three. Setting the cache size + * for X applies to X and leaves the settings for A and Y in tact. Interfaces can be passed to this method, but they + * only take effect if the cache size of a class or it's superclasses has been set. Just like Class.getInterfaces(), + * if multiple cache sizes are set, the interface names declared earliest in the implements clause of the eventClass + * takes effect. + *

+ *

+ * The cache for an event is not adjusted until the next event of that class is published. + *

+ * + * @param eventClass the class of event + * @param cacheSize the number of published events to cache for this event + */ + public void setCacheSizeForEventClass(Class eventClass, int cacheSize); + + /** + * Returns the number of events cached for a particular class of event. By default, no events are cached. + *

+ * This result is computed for a particular class from the values passed to #setCacheSizeForEventClass(Class, int), + * and respects the class hierarchy. + *

+ * + * @param eventClass the class of event + * + * @return the maximum size of the event cache for the given event class + * + * @see #setCacheSizeForEventClass(Class,int) + */ + public int getCacheSizeForEventClass(Class eventClass); + + /** + * Set the number of published data objects cached for a particular event topic. By default, no data are cached. + *

+ * This overrides any setting for the DefaultCacheSizePerClassOrTopic. + *

+ *

+ * Exact topic names take precedence over pattern matching. + *

+ *

+ * The cache for a topic is not adjusted until the next publication on that topic. + *

+ * + * @param topicName the topic name + * @param cacheSize the number of published data Objects to cache for this topic + */ + public void setCacheSizeForTopic(String topicName, int cacheSize); + + /** + * Set the number of published data objects cached for a topics matching a pattern. By default, no data are cached. + *

+ * This overrides any setting for the DefaultCacheSizePerClassOrTopic. + *

+ *

+ * Exact topic names take precedence over pattern matching. + *

+ *

+ * The cache for a topic is not adjusted until the next publication on that topic. + *

+ * + * @param pattern the pattern matching topic names + * @param cacheSize the number of data Objects to cache for this topic + */ + public void setCacheSizeForTopic(Pattern pattern, int cacheSize); + + /** + * Returns the number of cached data objects published on a particular topic. + *

+ * This result is computed for a particular class from the values passed to #setCacheSizeForEventClass(Class, int), + * and respects the class hierarchy. + *

+ * + * @param topic the topic name + * + * @return the maximum size of the data Object cache for the given topic + * + * @see #setCacheSizeForTopic(String,int) + * @see #setCacheSizeForTopic(java.util.regex.Pattern,int) + */ + public int getCacheSizeForTopic(String topic); + + /** + * When caching, returns the last event publish for the type supplied. + * @param eventClass an index into the cache + * + * @return the last event published for this event class, or null if caching is turned off (the default) + */ + public T getLastEvent(Class eventClass); + + /** + * When caching, returns the last set of event published for the type supplied. + * @param eventClass an index into the cache + * + * @return the last events published for this event class, or null if caching is turned off (the default) + */ + public List getCachedEvents(Class eventClass); + + /** + * When caching, returns the last payload published on the topic name supplied. + * @param topic an index into the cache + * + * @return the last data Object published on this topic, or null if caching is turned off (the default) + */ + public Object getLastTopicData(String topic); + + /** + * When caching, returns the last set of payload objects published on the topic name supplied. + * @param topic an index into the cache + * + * @return the last data Objects published on this topic, or null if caching is turned off (the default) + */ + public List getCachedTopicData(String topic); + + /** + * Clears the event cache for a specific event class or interface and it's any of it's subclasses or implementing + * classes. + * + * @param eventClass the event class to clear the cache for + */ + public void clearCache(Class eventClass); + + /** + * Clears the topic data cache for a specific topic name. + * + * @param topic the topic name to clear the cache for + */ + public void clearCache(String topic); + + /** + * Clears the topic data cache for all topics that match a particular pattern. + * + * @param pattern the pattern to match topic caches to + */ + public void clearCache(Pattern pattern); + + /** Clear all event caches for all topics and event. */ + public void clearCache(); + + /** + * Stop a subscription for an object that is subscribed with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements EventSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param eventClass class this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribe(Class eventClass, Object subscribedByProxy); + + /** + * Stop a subscription for an object that is subscribed exactly with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements EventSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param eventClass class this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribeExactly(Class eventClass, Object subscribedByProxy); + + /** + * Stop a subscription for an object that is subscribed to a topic with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements EventSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param topic the topic this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribe(String topic, Object subscribedByProxy); + + /** + * When using annotations, an object may be subscribed by proxy. This unsubscribe method will unsubscribe an object + * that is subscribed with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements EventSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param pattern the RegEx expression this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribe(Pattern pattern, Object subscribedByProxy); + + /** + * Stop a veto subscription for an object that is subscribed with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements VetoSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param eventClass class this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribeVeto(Class eventClass, Object subscribedByProxy); + + /** + * Stop a veto subscription for an object that is subscribed exactly with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements VetoSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param eventClass class this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribeVetoExactly(Class eventClass, Object subscribedByProxy); + + /** + * Stop a veto subscription for an object that is subscribed to a topic with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements EventSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param topic the topic this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribeVeto(String topic, Object subscribedByProxy); + + /** + * When using annotations, an object may be subscribed by proxy. This unsubscribe method will unsubscribe an object + * that is subscribed with a ProxySubscriber. + *

+ * If an object is subscribed by proxy and it implements EventSubscriber, then the normal unsubscribe methods will + * still unsubscribe the object. + *

+ * + * @param pattern the RegEx expression this object is subscribed to by proxy + * @param subscribedByProxy object subscribed by proxy + * @return true if the subscription was cancelled, false if it never existed + */ + boolean unsubscribeVeto(Pattern pattern, Object subscribedByProxy); +} diff --git a/src/main/java/org/scijava/event/bushe/EventSubscriber.java b/src/main/java/org/scijava/event/bushe/EventSubscriber.java new file mode 100644 index 000000000..03e8f9227 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/EventSubscriber.java @@ -0,0 +1,35 @@ +/** + * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com + * + * Licensed 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.scijava.event.bushe; + +/** + * Callback interface for class-based subscribers of an {@link EventService}. + * + * @author Michael Bushe michael@bushe.com + */ +public interface EventSubscriber { + + /** + * Handle a published event.

The EventService calls this method on each publication of an object that matches the + * class or interface passed to one of the EventService's class-based subscribe methods, specifically, {@link + * EventService#subscribe(Class,EventSubscriber)} {@link EventService#subscribeExactly(Class,EventSubscriber)} + * {@link EventService#subscribeStrongly(Class,EventSubscriber)} and {@link EventService#subscribeExactlyStrongly(Class, + *EventSubscriber)}. + * + * @param event The Object that is being published. + */ + public void onEvent(T event); +} diff --git a/src/main/java/org/scijava/event/bushe/EventTopicSubscriber.java b/src/main/java/org/scijava/event/bushe/EventTopicSubscriber.java new file mode 100644 index 000000000..37bf575e4 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/EventTopicSubscriber.java @@ -0,0 +1,39 @@ +/** + * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com + * + * Licensed 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.scijava.event.bushe; + +/** + * Callback interface for topic-based subscribers of an {@link EventService}. + * + * @author Michael Bushe michael@bushe.com + */ +interface EventTopicSubscriber { + + /** + * Handle an event published on a topic. + *

+ * The EventService calls this method on each publication on a matching topic name passed to one of the + * EventService's topic-based subscribe methods, specifically, {@link EventService#subscribe(String, + *EventTopicSubscriber)} {@link EventService#subscribe(java.util.regex.Pattern,EventTopicSubscriber)} {@link + * EventService#subscribeStrongly(String,EventTopicSubscriber)} and {@link EventService#subscribeStrongly(java.util.regex.Pattern, + *EventTopicSubscriber)}. + *

+ * + * @param topic the name of the topic published on + * @param data the data object published on the topic + */ + public void onEvent(String topic, T data); +} diff --git a/src/main/java/org/scijava/event/bushe/Logger.java b/src/main/java/org/scijava/event/bushe/Logger.java new file mode 100644 index 000000000..f2de3981b --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/Logger.java @@ -0,0 +1,221 @@ +package org.scijava.event.bushe; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.HashMap; + +/** + * Central Logging class. Shields code from Logging implementation. + *

+ * The EventBus allows operation in two modes - using java.util.logging so that + * the EventBus can be deployed in its own jar or using any logging system supported + * by apache commons logging, which of course requires other jars. + *

+ *

+ * The EventBus logging uses the names of its classes as the log, primarily + * "org.scijava.event.bushe.EventService". This aids in debugging which subscription and publication issues. + *

+ *

+ * Implementation note: There are no imports in this class to make things + * explicit. There is also no explicit use of classes outside java.util, + * anything else is used by reflection to avoid NoClassDefFound errors on class load. + *

+ */ +class Logger { + private java.util.logging.Logger utilLogger; + private /*Untyped to avoid java.lang.NoClassDefFoundError + org.apache.commons.logging.Log*/ Object commonsLogger; + private Map METHOD_CACHE_NO_PARAMS; + private Map METHOD_CACHE_ONE_PARAM; + private Map METHOD_CACHE_TWO_PARAMS; + private static Class logFactoryClass; + private static Class logClass; + private static Method getLogMethod; + private static final Object[] EMPTY_ARGS = new Object[0]; + private static final Class[] CLASS_ARGS_EMPTY = new Class[0]; + private static final Class[] CLASS_ARGS_ONE = new Class[]{Object.class}; + private static final Class[] CLASS_ARGS_TWO = new Class[]{Object.class, Throwable.class}; + + /** Allows switching between Java and Commons logging.*/ + public static enum LoggerType { + /*java.util.logging*/ + JAVA, + /*org.apache.commons.logging*/ + COMMONS + } + + /** Standardized logging levels. */ + public static enum Level { + FATAL, + ERROR, + WARN, + INFO, + DEBUG, + TRACE + } + + public static LoggerType LOGGER_TYPE= null; + + public static Logger getLogger(String name) { + if (LOGGER_TYPE == null) { + LOGGER_TYPE = getLoggerType(); + } + if (LOGGER_TYPE == LoggerType.COMMONS) { + try { + Object logger = getLogMethod.invoke(null, name); + return new Logger(logger); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + return new Logger(java.util.logging.Logger.getLogger(name)); + } + + /** + * This method should only be called once in a JVM run. + * @return + */ + private static LoggerType getLoggerType() { + LoggerType result = null; + //See if apache commons is available + try { + logFactoryClass = Class.forName("org.apache.commons.logging.LogFactory"); + getLogMethod = logFactoryClass.getMethod("getLog", new Class[]{String.class}); + logClass = Class.forName("org.apache.commons.logging.Log"); + return LoggerType.COMMONS; + } catch (Throwable e) { + } + return LoggerType.JAVA; + } + + public Logger(java.util.logging.Logger utilLogger) { + this.utilLogger = utilLogger; + } + + public Logger(Object commonsLogger) { + this.commonsLogger = commonsLogger; + } + + /** + * Returns whether this level is loggable. If there is + * a misconfiguration, this will always return false. + * @param level the EventBus Logger level + * @return whether this level is loggable. + */ + public boolean isLoggable(Level level) { + if (utilLogger != null) { + java.util.logging.Level javaLevel = getJavaLevelFor(level); + return javaLevel != null && utilLogger.isLoggable(javaLevel); + } else if (commonsLogger != null) { + switch (level) { + case ERROR: return (Boolean)callCommonsLogger("isErrorEnabled"); + case FATAL: return (Boolean)callCommonsLogger("isFatalEnabled"); + case WARN: return (Boolean)callCommonsLogger("isWarnEnabled"); + case INFO: return (Boolean)callCommonsLogger("isInfoEnabled"); + case DEBUG: return (Boolean)callCommonsLogger("isDebugEnabled"); + case TRACE: return (Boolean)callCommonsLogger("isTraceEnabled"); + } + } + return false; + } + + private java.util.logging.Level getJavaLevelFor(Level level) { + switch (level) { + case FATAL: return java.util.logging.Level.SEVERE; + case ERROR: return java.util.logging.Level.SEVERE; + case WARN: return java.util.logging.Level.WARNING; + case INFO: return java.util.logging.Level.INFO; + case DEBUG: return java.util.logging.Level.FINE; + case TRACE: return java.util.logging.Level.FINEST; + } + return null; + } + + public void debug(String message) { + log(Level.DEBUG, message); + } + + public void log(Level level, String message) { + log(level, message, null); + } + + public void log(Level level, String message, Throwable throwable) { + if (!isLoggable(level)) { + return; + } + if (utilLogger != null) { + java.util.logging.Level javaLevel = getJavaLevelFor(level); + if (throwable == null) { + utilLogger.log(javaLevel, message); + } else { + utilLogger.log(javaLevel, message, throwable); + } + } else if (commonsLogger != null) { + if (throwable == null) { + switch (level) { + case ERROR: callCommonsLogger("error", message); break; + case FATAL: callCommonsLogger("fatal", message); break; + case WARN: callCommonsLogger("warn", message); break; + case INFO: callCommonsLogger("info", message); break; + case DEBUG: callCommonsLogger("debug", message); break; + case TRACE: callCommonsLogger("trace", message); break; + } + } else { + switch (level) { + case ERROR: callCommonsLogger("error", message, throwable); break; + case FATAL: callCommonsLogger("fatal", message, throwable); break; + case WARN: callCommonsLogger("warn", message, throwable); break; + case INFO: callCommonsLogger("info", message, throwable); break; + case DEBUG: callCommonsLogger("debug", message, throwable); break; + case TRACE: callCommonsLogger("trace", message, throwable); break; + } + } + } + } + + private Object callCommonsLogger(String methodName) { + if (METHOD_CACHE_NO_PARAMS == null) { + METHOD_CACHE_NO_PARAMS = new HashMap(); + } + return callCommonsLogger(METHOD_CACHE_NO_PARAMS, methodName, CLASS_ARGS_EMPTY, EMPTY_ARGS); + } + + private Object callCommonsLogger(String methodName, String message) { + if (METHOD_CACHE_ONE_PARAM == null) { + METHOD_CACHE_ONE_PARAM = new HashMap(); + } + return callCommonsLogger(METHOD_CACHE_ONE_PARAM, methodName, CLASS_ARGS_ONE, new Object[]{message}); + } + + private Object callCommonsLogger(String methodName, String message, Throwable throwable) { + if (METHOD_CACHE_TWO_PARAMS == null) { + METHOD_CACHE_TWO_PARAMS = new HashMap(); + } + return callCommonsLogger(METHOD_CACHE_TWO_PARAMS, methodName, CLASS_ARGS_TWO, new Object[]{message, throwable}); + } + + private Object callCommonsLogger(Map cache, String methodName, Class[] classOfArgs, Object[] args) { + Method method = cache.get(methodName); + if (method == null) { + try { + method = logClass.getMethod(methodName, classOfArgs); + cache.put(methodName, method); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + if (method == null) { + return null; + } + try { + return method.invoke(commonsLogger, args); + } catch (IllegalAccessException e) { + return null; + } catch (InvocationTargetException e) { + return null; + } + } +} diff --git a/src/main/java/org/scijava/event/bushe/Prioritized.java b/src/main/java/org/scijava/event/bushe/Prioritized.java new file mode 100644 index 000000000..7a3187055 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/Prioritized.java @@ -0,0 +1,14 @@ +package org.scijava.event.bushe; + +/** + * Subscribers can implement this interface in order to affect the order in which they are called. + *

+ * Subscribers that do not implement this interface are called on a FIFO basis, as are subscribers that implement this + * interface and return 0. If the priority returned from this interface is negative, then this subscriber will be + * called before non-Prioritized subscribers, the more negative, the earlier it is called. If the priority returned + * from this interface is positive, then this subscriber will be called after non-Prioritized subscribers, the more + * positive, the later it is called. + */ +interface Prioritized { + int getPriority(); +} diff --git a/src/main/java/org/scijava/event/bushe/ProxySubscriber.java b/src/main/java/org/scijava/event/bushe/ProxySubscriber.java new file mode 100644 index 000000000..04ac3ce0a --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/ProxySubscriber.java @@ -0,0 +1,43 @@ +/** + * Copyright 2007 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com + * + * Licensed 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.scijava.event.bushe; + +/** + * An interface that can be implemented when proxies are used for subscription, not needed in normal usage. When an + * unsubscribe method is called on an EventService, the EventService is required to check if any of subscribed objects + * are ProxySubscribers and if the object to be unsubscribed is the ProxySubscriber's proxiedSubscriber. If so, the + * EventService proxy is unsubscribed and the ProxySubscriber's proxyUnsubscribed() method is called to allow the proxy + * to perform any cleanup if necessary. ProxySubscribers should set their references to their proxied objects to null + * for strong subscriptions to allow garbage collection. + * + * @author Michael Bushe + */ +interface ProxySubscriber { + + /** @return the object this proxy is subscribed on behalf of */ + public Object getProxiedSubscriber(); + + /** + * Called by EventServices to inform the proxy that it is unsubscribed. The ProxySubscriber should null the + * reference to it's proxied subscriber + */ + public void proxyUnsubscribed(); + + /** + * @return the reference strength from this proxy to the proxied subscriber + */ + public ReferenceStrength getReferenceStrength(); +} diff --git a/src/main/java/org/scijava/event/bushe/PublicationStatus.java b/src/main/java/org/scijava/event/bushe/PublicationStatus.java new file mode 100644 index 000000000..84c0090d0 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/PublicationStatus.java @@ -0,0 +1,30 @@ +package org.scijava.event.bushe; + +/** + * The status of an event as it makes its way from publication through processing by subscribers. + *

+ * EventServices are required to stamp any event object or payload that implements the PublicationStatusTracker + * with the corresponding PublicationStatus as the event object is processed. The EventService is not + * required to set the Unpublished state. + */ +enum PublicationStatus { + /** Recommended default.*/ + Unpublished, + /** Set directly after publication on an EventService.*/ + Initiated, + /** End status for events that are vetoed and never sent to subscribers.*/ + Vetoed, + /** State set after veto test is passed before the event is send to any subscribers.*/ + Queued, + /** Set while the event is sent to it's subscribers. EventService implementations + * such as the ThreadSafeEventService and the SwingEventService will transition from Queued to + * Publishing immediately. Others implementations that call subscribers on threads different + * from veto subscribers are free to leave an event in the Queued state and wait until + * the event is passed to the thread(s) that subscribers are called on to set the + * Publishing state */ + Publishing, + /** + * Called when all subscribers have finished handling the event publication. + */ + Completed +} diff --git a/src/main/java/org/scijava/event/bushe/PublicationStatusTracker.java b/src/main/java/org/scijava/event/bushe/PublicationStatusTracker.java new file mode 100644 index 000000000..cc6a98595 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/PublicationStatusTracker.java @@ -0,0 +1,24 @@ +package org.scijava.event.bushe; + +/** + * An optional interface that can be implemented by Events objects or topic Payloads + * to enable the events' status to be stamped on the event by an event service. + *

+ * EventService implementations must call setEventStatus(status) on event objects and + * payloads that implement this interface. + */ +interface PublicationStatusTracker { + + /** + * Implementations of this method must be made thread safe. + * @return last value set by setPublicationStatus(), or + * {@link PublicationStatus#Unpublished} if setPublicationStatus was never called. + */ + public PublicationStatus getPublicationStatus(); + + /** + * Implementations of this method must be made thread safe. + * @param status the status of the event during it's current publication + */ + public void setPublicationStatus(PublicationStatus status); +} diff --git a/src/main/java/org/scijava/event/bushe/ReferenceStrength.java b/src/main/java/org/scijava/event/bushe/ReferenceStrength.java new file mode 100644 index 000000000..15e7a7eb5 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/ReferenceStrength.java @@ -0,0 +1,11 @@ +package org.scijava.event.bushe; + +/** + * The two kinds of references that are used in the EventBus. + * + * @author Michael Bushe + */ +public enum ReferenceStrength { + WEAK, + STRONG +} diff --git a/src/main/java/org/scijava/event/bushe/SwingException.java b/src/main/java/org/scijava/event/bushe/SwingException.java new file mode 100644 index 000000000..f36fc36d6 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/SwingException.java @@ -0,0 +1,128 @@ +/** + * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com + * + * Licensed 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.scijava.event.bushe; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * Aids in troubleshooting Swing application exceptions or any exception where the caller's stack may not be the + * exception stack (such as producer-consumer patterns that cross threads). + *

+ * Swing exceptions usually occur on the Swing Event Dispatch Thread, and often occur when code puts events on the EDT. + * This code is often in a non-EDT thread such as a thread that is receiving data from a server. If the non-EDT threads + * puts a call on the EDT and that EDT call causes and exception, the stack trace of the exception is lost, and it often + * difficult or impossible to determine where the non-EDT call came from. + *

+ *

+ * This Exception class is used to handle exceptions that occur when events are posted on the Swing EDT or occur on + * another thread from the Swing EDT. It includes a "swing" call stack to record from where the event occurred, and + * overrides so that the exception and the swing calling stack print nicely to logs. + *

+ *

+ * The swing calling stack is different from the cause of the exception since it is gathered before the exception occurs + * in a different stack from the cause and used after the exception in a new thread occurs. + *

+ * + * @author Michael Bushe michael@bushe.com + */ +class SwingException extends Exception { + protected StackTraceElement[] callingStackTrace; + + /** Default constructor */ + public SwingException() { + super(); + } + + /** + * Constructor for compatibility with Exception. Use ClientException(String, Throwable, StackTraceElement[]) + * instead + */ + public SwingException(String message) { + super(message); + } + + /** Constructor for compatibility with Exception Use ClientException(String, Throwable, StackTraceElement[]) instead */ + public SwingException(Throwable cause) { + super(cause); + } + + /** Constructor for compatibility with Exception Use ClientException(String, Throwable, StackTraceElement[]) instead */ + public SwingException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Preferred constructor. + * + * @param message The message of exception + * @param cause The cause of the exception in the same call stack + * @param callingStack the stack trace that the client used to call the exception to occur. + */ + public SwingException(String message, Throwable cause, StackTraceElement[] callingStack) { + super(message, cause); + setCallingStack(callingStack); + } + + /** + * Swing exceptions often have two stacks - one thread causes the posting of an action on another thread - usually + * the Swing EDT thread. The other is the stack of the actual thread the exception occurred on, the exception occurs + * after the post. + * + * @param swingCallingStack the stack trace that the client used to cause the exception to occur. + */ + public void setCallingStack(StackTraceElement[] swingCallingStack) { + this.callingStackTrace = swingCallingStack; + } + + /** + * Client exceptions often have two stacks - one thread causes the posting of an action on another thread - usually + * the Swing EDT thread. The other is the stack of the actual thread the exception occurred on. + * + * @return the stack trace that the client used to cause the exception to occur. + */ + public StackTraceElement[] getCallingStack() { + return callingStackTrace; + } + + /** + * Calls printWriter(ps, true) + * + * @param ps the print stream + */ + public void printStackTrace(PrintStream ps) { + PrintWriter pw = new PrintWriter(ps, true); + printStackTrace(pw); + } + + /** + * Prints the calling stack and the exception stack trace. + * + * @param pw + */ + public void printStackTrace(PrintWriter pw) { + pw.println(this); + if (callingStackTrace != null) { + pw.println("Calling stack:"); + for (int i = 0; i < callingStackTrace.length; i++) { + pw.println("\tat " + callingStackTrace[i]); + } + pw.println("Stack after call:"); + } + super.printStackTrace(pw); + } +} + diff --git a/src/main/java/org/scijava/event/bushe/ThreadSafeEventService.java b/src/main/java/org/scijava/event/bushe/ThreadSafeEventService.java new file mode 100644 index 000000000..920d0add4 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/ThreadSafeEventService.java @@ -0,0 +1,2180 @@ +/** + * Copyright 2005-2007 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com + * + * Licensed 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.scijava.event.bushe; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Type; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.WildcardType; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Collections; +import java.util.Comparator; +import java.util.regex.Pattern; + +import org.scijava.event.bushe.Logger.Level; + +/** + * A thread-safe EventService implementation. + *

Multithreading

+ *

+ * This implementation is not Swing thread-safe. If publication occurs on a thread other than the Swing + * EventDispatchThread, subscribers will receive the event on the calling thread, and not the EDT. Swing components + * should use the SwingEventService instead, which is the implementation used by the EventBus. + *

+ *

+ * Two threads may be accessing the ThreadSafeEventService at the same time, one unsubscribing a + * listener for topic "A" and the other publishing on topic "A". If the unsubscribing thread gets the lock first, + * then it is unsubscribed, end of story. If the publisher gets the lock first, then a snapshot copy of the current + * subscribers is made during the publication, the lock is released and the subscribers are called. Between the time + * the lock is released and the time that the listener is called, the unsubscribing thread can unsubscribe, resulting + * in an unsubscribed object receiving notification of the event after it was unsubscribed (but just once). + *

+ *

+ * On event publication, subscribers are called in the order in which they subscribed. + *

+ *

+ * Events and/or topic data can be cached, but are not by default. To cache events or topic data, call + * {@link #setDefaultCacheSizePerClassOrTopic(int)}, {@link #setCacheSizeForEventClass(Class, int)}, or + * {@link #setCacheSizeForTopic(String, int)}, {@link #setCacheSizeForTopic(Pattern, int)}. Retrieve cached values + * with {@link #getLastEvent(Class)}, {@link #getLastTopicData(String)}, {@link #getCachedEvents(Class)}, or + * {@link #getCachedTopicData(String)}. Using caching while subscribing + * is most likely to make sense only if you subscribe and publish on the same thread (so caching is very useful for + * Swing applications since both happen on the EDT in a single-threaded manner). In multithreaded applications, you + * never know if your subscriber has handled an event while it was being subscribed (before the subscribe() method + * returned) that is newer or older than the retrieved cached value (taken before or after subscribe() respectively). + *

+ *

Logging

+ *

+ * All logging goes through the {@link Logger}. The Logger is configurable and supports multiple logging systems. + *

+ *

+ * Exceptions are logged by default, override {@link #handleException(String,Object,String,Object,Throwable, + * StackTraceElement[],String)} to handleException exceptions in another way. Each call to a subscriber is wrapped in + * a try block to ensure one listener does not interfere with another. + *

+ *

Cleanup of Stale WeakReferences and Stale Annotation Proxies

+ *

+ * The EventService may need to clean up stale WeakReferences and ProxySubscribers created for EventBus annotations. (Aside: EventBus + * Annotations are handled by the creation of proxies to the annotated objects. Since the annotations create weak references + * by default, annotation proxies must held strongly by the EventService, otherwise the proxy is garbage collected.) When + * a WeakReference's referent or an ProxySubscriber's proxiedObject (the annotated object) is claimed by the garbage collector, + * the EventService still holds onto the actual WeakReference or ProxySubscriber subscribed to the EventService (which are pretty tiny). + *

+ *

+ * There are two ways that these stale WeakReferences and ProxySubscribers are cleaned up. + *

+ *
    + *
  1. On every publish, subscribe and unsubscribe, every subscriber and veto subscriber to a class or topic is checked to see + * if it is a stale WeakReference or a stale ProxySubscriber (one whose getProxySubscriber() returns null). If the subscriber + * is stale, it is unsubscribed from the EventService immediately. If it is a ProxySubscriber, it's proxyUnsubscribed() + * method is called after it is unsubscribed. (This isn't as expensive as it sounds, since checks to avoid double subscription is + * necessary anyway). + *
  2. Another cleanup thread may get started to clean up remaining stale subscribers. This cleanup thread only comes into + * play for subscribers to topic or classes that haven't been used (published/subscribed/unsibscribed to). A detailed description + * of the cleanup thread follows. + *
+ *

The Cleanup Thread

+ *

+ * If a topic or class is never published to again, WeakReferences and ProxySubscribers can be left behind if they + * are not cleaned up. To prevent loitering stale subscribers, the ThreadSafeEventService may periodically run through + * all the EventSubscribers and VetoSubscribers for all topics and classes and clean up stale proxies. Proxies for + * Annotations that have a ReferenceStrength.STRONG are never cleaned up in normal usage. (By specifying + * ReferenceStrength.STRONG, the programmer is buying into unsubscribing annotated objects themselves. There is + * one caveat: If getProxiedSubscriber() returns null, even for a ProxySubscriber with a STRONG reference strength, that proxy + * is cleaned up as it is assumed it is stale or just wrong. This would not occur normally in EventBus usage, but only + * if someone is implementing their own custom ProxySubscriber and/or AnnotationProcessor.) + *

+ *

+ * Cleanup is pretty rare in general. Not only are stale subscribers cleaned up with regular usage, stale + * subscribers on abandoned topics and classes do not take up a lot of memory, hence, they are allowed to build up to a certain degree. + * Cleanup does not occur until the number of WeakReferences and SubscriptionsProxy's with WeakReference strength + * subscribed to an EventService for all the EventService's subscriptions in total exceed the cleanupStartThreshhold, + * which is set to CLEANUP_START_THRESHOLD_DEFAULT (500) by default. The default is overridable in the constructor + * or via #setCleanupStartThreshhold(Integer). If set to null, cleanup will never start. + *

+ *

+ * Once the cleanup start threshold is exceeded, a java.util.Timer is started to clean up stale subscribers periodically + * in another thread. The timer will fire every cleanupPeriodMS milliseconds, which is set to the + * CLEANUP_PERIOD_MS_DEFAULT (20 minutes) by default. The default is overridable in the constructor or + * via #setCleanupPeriodMS(Integer). If set to null, cleanup will not start. This is implemented with a java.util.Timer, + * so Timer's warnings apply - setting this too low will cause cleanups to bunch up and hog the cleanup thread. + *

+ *

+ * After a cleanup cycle completes, if the number of stale subscribers falls at or below the cleanupStopThreshhold + * cleanup stops until the cleanupStartThreshhold is exceeded again. The cleanupStopThreshhold is set + * to CLEANUP_STOP_THRESHOLD_DEFAULT (100) by default. The default is overridable in the constructor or via + * #setCleanupStopThreshhold(Integer). If set to null or 0, cleanup will not stop if it is ever started. + *

+ *

+ * All cleanup parameters are tunable "live" and checked after each subscription and after each cleanup cycle. + * To make cleanup never run, set cleanupStartThreshhold to Integer.MAX_VALUE and cleanupPeriodMS to null. + * To get cleanup to run continuously, set set cleanupStartThreshhold to 0 and cleanupPeriodMS to some reasonable value, + * perhaps 1000 (1 second) or so (not recommended, cleanup is conducted with regular usage and the cleanup thread is + * rarely created or invoked). + *

+ *

+ * Cleanup is not run in a daemon thread, and thus will not stop the JVM from exiting. + *

+ * + * @author Michael Bushe michael@bushe.com + * @see EventService for a complete description of the API + */ +@SuppressWarnings({"unchecked"}) +public class ThreadSafeEventService implements EventService { + public static final Integer CLEANUP_START_THRESHOLD_DEFAULT = 250; + public static final Integer CLEANUP_STOP_THRESHOLD_DEFAULT = 100; + public static final Long CLEANUP_PERIOD_MS_DEFAULT = 20L*60L*1000L; + + protected static final Logger LOG = Logger.getLogger(EventService.class.getName()); + + //Making these generic collections is a bad idea, it doesn't compile since it's better to have all the maps + //go through the same set of code to do all the real publish and subscribe work + private Map subscribersByEventType = new HashMap(); + private Map subscribersByEventClass = new HashMap(); + private Map subscribersByExactEventClass = new HashMap(); + private Map subscribersByTopic = new HashMap(); + private Map subscribersByTopicPattern = new HashMap(); + private Map vetoListenersByClass = new HashMap(); + private Map vetoListenersByExactClass = new HashMap(); + private Map vetoListenersByTopic = new HashMap(); + private Map vetoListenersByTopicPattern = new HashMap(); + private final Object listenerLock = new Object(); + private final Object cacheLock = new Object(); + private Long timeThresholdForEventTimingEventPublication; + private Map cacheByEvent = new HashMap(); + private int defaultCacheSizePerClassOrTopic = 0; + private Map cacheSizesForEventClass; + private Map rawCacheSizesForEventClass; + private boolean rawCacheSizesForEventClassChanged; + private Map cacheByTopic = new HashMap(); + private Map cacheSizesForTopic; + private Map rawCacheSizesForTopic; + private boolean rawCacheSizesForTopicChanged; + private Map rawCacheSizesForPattern; + private boolean rawCacheSizesForPatternChanged; + private Integer cleanupStartThreshhold; + private Integer cleanupStopThreshold; + private Long cleanupPeriodMS; + private int weakRefPlusProxySubscriberCount; + private Timer cleanupTimer; + private TimerTask cleanupTimerTask; + private static final Comparator PRIORITIZED_SUBSCRIBER_COMPARATOR = new PrioritizedSubscriberComparator(); + private boolean hasEverUsedPrioritized; + + /** Creates a ThreadSafeEventService that does not monitor timing of handlers. */ + public ThreadSafeEventService() { + this(null, null, null, null); + } + + /** + * Creates a ThreadSafeEventService while providing time monitoring options. + * + * @param timeThresholdForEventTimingEventPublication the longest time a subscriber should spend handling an event, + * The service will publish an SubscriberTimingEvent after listener processing if the time was exceeded. If null, no + * EventSubscriberTimingEvent will be issued. + */ + public ThreadSafeEventService(Long timeThresholdForEventTimingEventPublication) { + this(timeThresholdForEventTimingEventPublication, null, null, null); + } + + /** + * Creates a ThreadSafeEventService while providing proxy cleanup customization. + * Proxies are used with Annotations. + * + * @param cleanupStartThreshold see class javadoc. + * @param cleanupStopThreshold see class javadoc. + * @param cleanupPeriodMS see class javadoc. + */ + public ThreadSafeEventService(Integer cleanupStartThreshold, + Integer cleanupStopThreshold, Long cleanupPeriodMS) { + this(null, cleanupStartThreshold, cleanupStopThreshold, cleanupPeriodMS); + } + + /** + * Creates a ThreadSafeEventService while providing time monitoring options. + * + * @param timeThresholdForEventTimingEventPublication the longest time a subscriber should spend handling an event. + * The service will publish an SubscriberTimingEvent after listener processing if the time was exceeded. If null, no + * SubscriberTimingEvent will be issued. + * @param cleanupStartThreshold see class javadoc. + * @param cleanupStopThreshold see class javadoc. + * @param cleanupPeriodMS see class javadoc. + */ + public ThreadSafeEventService(Long timeThresholdForEventTimingEventPublication, + Integer cleanupStartThreshold, Integer cleanupStopThreshold, Long cleanupPeriodMS) { + this.timeThresholdForEventTimingEventPublication = timeThresholdForEventTimingEventPublication; + if (cleanupStartThreshold == null) { + this.cleanupStartThreshhold = CLEANUP_START_THRESHOLD_DEFAULT; + } else { + this.cleanupStartThreshhold = cleanupStartThreshold; + } + if (cleanupStopThreshold == null) { + this.cleanupStopThreshold = CLEANUP_STOP_THRESHOLD_DEFAULT; + } else { + this.cleanupStopThreshold = cleanupStopThreshold; + } + if (cleanupPeriodMS == null) { + this.cleanupPeriodMS = CLEANUP_PERIOD_MS_DEFAULT; + } else { + this.cleanupPeriodMS = cleanupPeriodMS; + } + } + + /** + * Gets the threshold above which cleanup starts. See the class javadoc on cleanup. + * @return the threshold at which cleanup starts + */ + public Integer getCleanupStartThreshhold() { + synchronized (listenerLock) { + return cleanupStartThreshhold; + } + } + + /** + * Sets the threshold above which cleanup starts. See the class javadoc on cleanup. + * @param cleanupStartThreshhold threshold at which cleanup starts + */ + public void setCleanupStartThreshhold(Integer cleanupStartThreshhold) { + synchronized (listenerLock) { + this.cleanupStartThreshhold = cleanupStartThreshhold; + } + } + + /** + * Gets the threshold below which cleanup stops. See the class javadoc on cleanup. + * @return threshold at which cleanup stops (it may start again) + */ + public Integer getCleanupStopThreshold() { + synchronized (listenerLock) { + return cleanupStopThreshold; + } + } + + /** + * Sets the threshold below which cleanup stops. See the class javadoc on cleanup. + * @param cleanupStopThreshold threshold at which cleanup stops (it may start again). + */ + public void setCleanupStopThreshold(Integer cleanupStopThreshold) { + synchronized (listenerLock) { + this.cleanupStopThreshold = cleanupStopThreshold; + } + } + + /** + * Get the cleanup interval. See the class javadoc on cleanup. + * @return interval in milliseconds between cleanup runs. + */ + public Long getCleanupPeriodMS() { + synchronized (listenerLock) { + return cleanupPeriodMS; + } + } + + /** + * Sets the cleanup interval. See the class javadoc on cleanup. + * @param cleanupPeriodMS interval in milliseconds between cleanup runs. Passing null + * stops cleanup. + */ + public void setCleanupPeriodMS(Long cleanupPeriodMS) { + synchronized (listenerLock) { + this.cleanupPeriodMS = cleanupPeriodMS; + } + } + + /** @see EventService#subscribe(Class,EventSubscriber) */ + public boolean subscribe(Class cl, EventSubscriber eh) { + if (cl == null) { + throw new IllegalArgumentException("Event class must not be null"); + } + if (eh == null) { + throw new IllegalArgumentException("Event subscriber must not be null"); + } + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing by class, class:" + cl + ", subscriber:" + eh); + } + return subscribe(cl, subscribersByEventClass, new WeakReference(eh)); + } + + /** @see EventService#subscribe(java.lang.reflect.Type, EventSubscriber) */ + public boolean subscribe(Type type, EventSubscriber eh) { + return subscribe(type, subscribersByEventType, new WeakReference(eh)); + } + + /** @see EventService#subscribeExactly(Class,EventSubscriber) */ + public boolean subscribeExactly(Class cl, EventSubscriber eh) { + if (cl == null) { + throw new IllegalArgumentException("Event class must not be null"); + } + if (eh == null) { + throw new IllegalArgumentException("Event subscriber must not be null"); + } + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing by class, class:" + cl + ", subscriber:" + eh); + } + return subscribe(cl, subscribersByExactEventClass, new WeakReference(eh)); + } + + /** @see EventService#subscribe(String,EventTopicSubscriber) */ + public boolean subscribe(String topic, EventTopicSubscriber eh) { + if (topic == null) { + throw new IllegalArgumentException("Topic must not be null"); + } + if (eh == null) { + throw new IllegalArgumentException("Event topic subscriber must not be null"); + } + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing by topic name, name:" + topic + ", subscriber:" + eh); + } + return subscribe(topic, subscribersByTopic, new WeakReference(eh)); + } + + /** @see EventService#subscribe(Pattern,EventTopicSubscriber) */ + public boolean subscribe(Pattern pat, EventTopicSubscriber eh) { + if (pat == null) { + throw new IllegalArgumentException("Pattern must not be null"); + } + if (eh == null) { + throw new IllegalArgumentException("Event subscriber must not be null"); + } + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing by pattern, pattern:" + pat + ", subscriber:" + eh); + } + PatternWrapper patternWrapper = new PatternWrapper(pat); + return subscribe(patternWrapper, subscribersByTopicPattern, new WeakReference(eh)); + } + + /** @see EventService#subscribeStrongly(Class,EventSubscriber) */ + public boolean subscribeStrongly(Class cl, EventSubscriber eh) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing weakly by class, class:" + cl + ", subscriber:" + eh); + } + if (eh == null) { + throw new IllegalArgumentException("Subscriber cannot be null."); + } + return subscribe(cl, subscribersByEventClass, eh); + } + + /** @see EventService#subscribeExactlyStrongly(Class,EventSubscriber) */ + public boolean subscribeExactlyStrongly(Class cl, EventSubscriber eh) { + if (cl == null) { + throw new IllegalArgumentException("Event class must not be null"); + } + if (eh == null) { + throw new IllegalArgumentException("Event subscriber must not be null"); + } + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing by class, class:" + cl + ", subscriber:" + eh); + } + return subscribe(cl, subscribersByExactEventClass, eh); + } + + /** @see EventService#subscribeStrongly(String,EventTopicSubscriber) */ + public boolean subscribeStrongly(String name, EventTopicSubscriber eh) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing weakly by topic name, name:" + name + ", subscriber:" + eh); + } + if (eh == null) { + throw new IllegalArgumentException("Subscriber cannot be null."); + } + return subscribe(name, subscribersByTopic, eh); + } + + /** @see EventService#subscribeStrongly(Pattern,EventTopicSubscriber) */ + public boolean subscribeStrongly(Pattern pat, EventTopicSubscriber eh) { + if (pat == null) { + throw new IllegalArgumentException("Pattern must not be null"); + } + if (eh == null) { + throw new IllegalArgumentException("Event subscriber must not be null"); + } + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Subscribing by pattern, pattern:" + pat + ", subscriber:" + eh); + } + PatternWrapper patternWrapper = new PatternWrapper(pat); + return subscribe(patternWrapper, subscribersByTopicPattern, eh); + } + + + /** @see org.scijava.event.bushe.EventService#clearAllSubscribers() */ + public void clearAllSubscribers() { + synchronized (listenerLock) { + unsubscribeAllInMap(subscribersByEventType); + unsubscribeAllInMap(subscribersByEventClass); + unsubscribeAllInMap(subscribersByExactEventClass); + unsubscribeAllInMap(subscribersByTopic); + unsubscribeAllInMap(subscribersByTopicPattern); + unsubscribeAllInMap(vetoListenersByClass); + unsubscribeAllInMap(vetoListenersByExactClass); + unsubscribeAllInMap(vetoListenersByTopic); + unsubscribeAllInMap(vetoListenersByTopicPattern); + } + } + + private void unsubscribeAllInMap(Map subscriberMap) { + synchronized (listenerLock) { + Set subscriptionKeys = subscriberMap.keySet(); + for (Object key : subscriptionKeys) { + List subscribers = (List) subscriberMap.get(key); + while (!subscribers.isEmpty()) { + unsubscribe(key, subscriberMap, subscribers.get(0)); + } + } + } + } + + /** @see EventService#subscribeVetoListener(Class,VetoEventListener) */ + public boolean subscribeVetoListener(Class eventClass, VetoEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoEventListener cannot be null."); + } + if (eventClass == null) { + throw new IllegalArgumentException("eventClass cannot be null."); + } + return subscribeVetoListener(eventClass, vetoListenersByClass, new WeakReference(vetoListener)); + } + + /** @see EventService#subscribeVetoListenerExactly(Class,VetoEventListener) */ + public boolean subscribeVetoListenerExactly(Class eventClass, VetoEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoEventListener cannot be null."); + } + if (eventClass == null) { + throw new IllegalArgumentException("eventClass cannot be null."); + } + return subscribeVetoListener(eventClass, vetoListenersByExactClass, new WeakReference(vetoListener)); + } + + /** @see EventService#subscribeVetoListener(String,VetoTopicEventListener) */ + public boolean subscribeVetoListener(String topic, VetoTopicEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoEventListener cannot be null."); + } + if (topic == null) { + throw new IllegalArgumentException("topic cannot be null."); + } + return subscribeVetoListener(topic, vetoListenersByTopic, new WeakReference(vetoListener)); + } + + /** @see EventService#subscribeVetoListener(Pattern,VetoTopicEventListener) */ + public boolean subscribeVetoListener(Pattern topicPattern, VetoTopicEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoEventListener cannot be null."); + } + if (topicPattern == null) { + throw new IllegalArgumentException("topicPattern cannot be null."); + } + PatternWrapper patternWrapper = new PatternWrapper(topicPattern); + return subscribeVetoListener(patternWrapper, vetoListenersByTopicPattern, new WeakReference(vetoListener)); + } + + /** @see EventService#subscribeVetoListenerStrongly(Class,VetoEventListener) */ + public boolean subscribeVetoListenerStrongly(Class eventClass, VetoEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoEventListener cannot be null."); + } + if (eventClass == null) { + throw new IllegalArgumentException("eventClass cannot be null."); + } + return subscribeVetoListener(eventClass, vetoListenersByClass, vetoListener); + } + + /** @see EventService#subscribeVetoListenerExactlyStrongly(Class,VetoEventListener) */ + public boolean subscribeVetoListenerExactlyStrongly(Class eventClass, VetoEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoEventListener cannot be null."); + } + if (eventClass == null) { + throw new IllegalArgumentException("eventClass cannot be null."); + } + return subscribeVetoListener(eventClass, vetoListenersByExactClass, vetoListener); + } + + /** @see EventService#subscribeVetoListenerStrongly(String,VetoTopicEventListener) */ + public boolean subscribeVetoListenerStrongly(String topic, VetoTopicEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoListener cannot be null."); + } + if (topic == null) { + throw new IllegalArgumentException("topic cannot be null."); + } + return subscribeVetoListener(topic, vetoListenersByTopic, vetoListener); + } + + /** @see EventService#subscribeVetoListenerStrongly(Pattern,VetoTopicEventListener) */ + public boolean subscribeVetoListenerStrongly(Pattern topicPattern, VetoTopicEventListener vetoListener) { + if (vetoListener == null) { + throw new IllegalArgumentException("VetoTopicEventListener cannot be null."); + } + if (topicPattern == null) { + throw new IllegalArgumentException("topicPattern cannot be null."); + } + PatternWrapper patternWrapper = new PatternWrapper(topicPattern); + return subscribeVetoListener(patternWrapper, vetoListenersByTopicPattern, vetoListener); + } + + /** + * All veto subscriptions methods call this method. Extending classes only have to override this method to subscribe + * all veto subscriptions. + * + * @param subscription the topic, Pattern, or event class to subscribe to + * @param vetoListenerMap the internal map of veto listeners to use (by topic of class) + * @param vetoListener the veto listener to subscribe, may be a VetoEventListener or a WeakReference to one + * + * @return boolean if the veto listener is subscribed (was not subscribed). + * + * @throws IllegalArgumentException if vl or o is null + */ + protected boolean subscribeVetoListener(final Object subscription, final Map vetoListenerMap, final Object vetoListener) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("subscribeVetoListener(" + subscription + "," + vetoListener + ")"); + } + if (vetoListener == null) { + throw new IllegalArgumentException("Can't subscribe null veto listener to " + subscription); + } + if (subscription == null) { + throw new IllegalArgumentException("Can't subscribe veto listener to null."); + } + return subscribe(subscription, vetoListenerMap, vetoListener); + } + + /** + * All subscribe methods call this method, including veto subscriptions. + * Extending classes only have to override this method to subscribe all + * subscriber subscriptions. + *

+ * Overriding this method is only for the adventurous. This basically gives you just enough rope to hang yourself. + *

+ * + * @param classTopicOrPatternWrapper the topic String, event Class, or PatternWrapper to subscribe to + * @param subscriberMap the internal map of subscribers to use (by topic or class) + * @param subscriber the EventSubscriber or EventTopicSubscriber to subscribe, or a WeakReference to either + * + * @return boolean if the subscriber is subscribed (was not subscribed). + * + * @throws IllegalArgumentException if subscriber or topicOrClass is null + */ + protected boolean subscribe(final Object classTopicOrPatternWrapper, final Map subscriberMap, final Object subscriber) { + if (classTopicOrPatternWrapper == null) { + throw new IllegalArgumentException("Can't subscribe to null."); + } + if (subscriber == null) { + throw new IllegalArgumentException("Can't subscribe null subscriber to " + classTopicOrPatternWrapper); + } + boolean alreadyExists = false; + + //Find the real subscriber underlying weak refs and proxies + Object realSubscriber = subscriber; + boolean isWeakRef = subscriber instanceof WeakReference; + if (isWeakRef) { + realSubscriber = ((WeakReference) subscriber).get(); + } + if (realSubscriber instanceof Prioritized) { + hasEverUsedPrioritized = true; + } + boolean isWeakProxySubscriber = false; + if (subscriber instanceof ProxySubscriber) { + ProxySubscriber proxySubscriber = (ProxySubscriber) subscriber; + if (proxySubscriber instanceof Prioritized) { + hasEverUsedPrioritized = true; + } + isWeakProxySubscriber = proxySubscriber.getReferenceStrength() == ReferenceStrength.WEAK; + if (isWeakProxySubscriber) { + realSubscriber = ((ProxySubscriber) subscriber).getProxiedSubscriber(); + } + } + if (isWeakRef && isWeakProxySubscriber) { + throw new IllegalArgumentException("ProxySubscribers should always be subscribed strongly."); + } + if (realSubscriber == null) { + return false;//already garbage collected? Weird. + } + synchronized (listenerLock) { + List currentSubscribers = (List) subscriberMap.get(classTopicOrPatternWrapper); + if (currentSubscribers == null) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Creating new subscriber map for:" + classTopicOrPatternWrapper); + } + currentSubscribers = new ArrayList(); + subscriberMap.put(classTopicOrPatternWrapper, currentSubscribers); + } else { + //Double subscription check and stale subscriber cleanup + //Need to compare the underlying referents for WeakReferences and ProxySubscribers + //to make sure a weak ref and a hard ref aren't both subscribed + //to the same topic and object. + //Use the proxied subscriber for comparison if a ProxySubscribers is used + //Subscribing the same object by proxy and subscribing explicitly should + //not subscribe the same object twice + for (Iterator iterator = currentSubscribers.iterator(); iterator.hasNext();) { + Object currentSubscriber = iterator.next(); + Object realCurrentSubscriber = getRealSubscriberAndCleanStaleSubscriberIfNecessary(iterator, currentSubscriber); + if (realSubscriber.equals(realCurrentSubscriber)) { + //Already subscribed. + //Remove temporarily, to add to the end of the calling list + iterator.remove(); + alreadyExists = true; + } + } + } + currentSubscribers.add(subscriber); + if (isWeakProxySubscriber || isWeakRef) { + incWeakRefPlusProxySubscriberCount(); + } + return !alreadyExists; + } + } + + /** @see EventService#unsubscribe(Class,EventSubscriber) */ + public boolean unsubscribe(Class cl, EventSubscriber eh) { + return unsubscribe(cl, subscribersByEventClass, eh); + } + + /** @see EventService#unsubscribeExactly(Class,EventSubscriber) */ + public boolean unsubscribeExactly(Class cl, EventSubscriber eh) { + return unsubscribe(cl, subscribersByExactEventClass, eh); + } + + /** @see EventService#unsubscribe(String,EventTopicSubscriber) */ + public boolean unsubscribe(String name, EventTopicSubscriber eh) { + return unsubscribe(name, subscribersByTopic, eh); + } + + /** @see EventService#unsubscribe(String,EventTopicSubscriber) */ + public boolean unsubscribe(Pattern topicPattern, EventTopicSubscriber eh) { + PatternWrapper patternWrapper = new PatternWrapper(topicPattern); + return unsubscribe(patternWrapper, subscribersByTopicPattern, eh); + } + + /** @see EventService#unsubscribe(Class,Object) */ + public boolean unsubscribe(Class eventClass, Object subscribedByProxy) { + EventSubscriber subscriber = (EventSubscriber) getProxySubscriber(eventClass, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribe(eventClass, subscriber); + } + } + + /** @see EventService#unsubscribeExactly(Class,Object) */ + public boolean unsubscribeExactly(Class eventClass, Object subscribedByProxy) { + EventSubscriber subscriber = (EventSubscriber) getProxySubscriber(eventClass, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribeExactly(eventClass, subscriber); + } + } + + /** @see EventService#unsubscribe(String,Object) */ + public boolean unsubscribe(String topic, Object subscribedByProxy) { + EventTopicSubscriber subscriber = (EventTopicSubscriber) getProxySubscriber(topic, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribe(topic, subscriber); + } + } + + /** @see EventService#unsubscribe(java.util.regex.Pattern,Object) */ + public boolean unsubscribe(Pattern pattern, Object subscribedByProxy) { + EventTopicSubscriber subscriber = (EventTopicSubscriber) getProxySubscriber(pattern, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribe(pattern, subscriber); + } + } + + /** + * All event subscriber unsubscriptions call this method. Extending classes only have to override this method to + * subscribe all subscriber unsubscriptions. + * + * @param o the topic or event class to unsubscribe from + * @param subscriberMap the map of subscribers to use (by topic of class) + * @param subscriber the subscriber to unsubscribe, either an EventSubscriber or an EventTopicSubscriber, or a WeakReference + * to either + * + * @return boolean if the subscriber is unsubscribed (was subscribed). + */ + protected boolean unsubscribe(Object o, Map subscriberMap, Object subscriber) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("unsubscribe(" + o + "," + subscriber + ")"); + } + if (o == null) { + throw new IllegalArgumentException("Can't unsubscribe to null."); + } + if (subscriber == null) { + throw new IllegalArgumentException("Can't unsubscribe null subscriber to " + o); + } + synchronized (listenerLock) { + return removeFromSetResolveWeakReferences(subscriberMap, o, subscriber); + } + } + + /** @see EventService#unsubscribeVeto(Class,Object) */ + public boolean unsubscribeVeto(Class eventClass, Object subscribedByProxy) { + VetoEventListener subscriber = (VetoEventListener) getVetoProxySubscriber(eventClass, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribeVetoListener(eventClass, subscriber); + } + } + + /** @see EventService#unsubscribeVetoExactly(Class,Object) */ + public boolean unsubscribeVetoExactly(Class eventClass, Object subscribedByProxy) { + VetoEventListener subscriber = (VetoEventListener) getVetoProxySubscriber(eventClass, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribeVetoListenerExactly(eventClass, subscriber); + } + } + + /** @see EventService#unsubscribeVeto(String,Object) */ + public boolean unsubscribeVeto(String topic, Object subscribedByProxy) { + VetoTopicEventListener subscriber = (VetoTopicEventListener) getVetoProxySubscriber(topic, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribeVetoListener(topic, subscriber); + } + } + + /** @see EventService#unsubscribeVeto(java.util.regex.Pattern,Object) */ + public boolean unsubscribeVeto(Pattern pattern, Object subscribedByProxy) { + VetoTopicEventListener subscriber = (VetoTopicEventListener) getVetoProxySubscriber(pattern, subscribedByProxy); + if (subscriber == null) { + return false; + } else { + return unsubscribeVetoListener(pattern, subscriber); + } + } + + /** @see EventService#unsubscribeVetoListener(Class,VetoEventListener) */ + public boolean unsubscribeVetoListener(Class eventClass, VetoEventListener vetoListener) { + return unsubscribeVetoListener(eventClass, vetoListenersByClass, vetoListener); + } + + /** @see EventService#unsubscribeVetoListenerExactly(Class,VetoEventListener) */ + public boolean unsubscribeVetoListenerExactly(Class eventClass, VetoEventListener vetoListener) { + return unsubscribeVetoListener(eventClass, vetoListenersByExactClass, vetoListener); + } + + /** @see EventService#unsubscribeVetoListener(String,VetoTopicEventListener) */ + public boolean unsubscribeVetoListener(String topic, VetoTopicEventListener vetoListener) { + return unsubscribeVetoListener(topic, vetoListenersByTopic, vetoListener); + } + + /** @see EventService#unsubscribeVetoListener(Pattern,VetoTopicEventListener) */ + public boolean unsubscribeVetoListener(Pattern topicPattern, VetoTopicEventListener vetoListener) { + PatternWrapper patternWrapper = new PatternWrapper(topicPattern); + return unsubscribeVetoListener(patternWrapper, vetoListenersByTopicPattern, vetoListener); + } + + /** + * All veto unsubscriptions methods call this method. Extending classes only have to override this method to + * subscribe all veto unsubscriptions. + * + * @param o the topic or event class to unsubscribe from + * @param vetoListenerMap the map of veto listeners to use (by topic or class) + * @param vl the veto listener to unsubscribe, or a WeakReference to one + * + * @return boolean if the veto listener is unsubscribed (was subscribed). + */ + protected boolean unsubscribeVetoListener(Object o, Map vetoListenerMap, Object vl) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("unsubscribeVetoListener(" + o + "," + vl + ")"); + } + if (o == null) { + throw new IllegalArgumentException("Can't unsubscribe veto listener to null."); + } + if (vl == null) { + throw new IllegalArgumentException("Can't unsubscribe null veto listener to " + o); + } + synchronized (listenerLock) { + return removeFromSetResolveWeakReferences(vetoListenerMap, o, vl); + } + } + + private ProxySubscriber getProxySubscriber(Class eventClass, Object subscribedByProxy) { + List subscribers = getSubscribers(eventClass); + return getProxySubscriber(subscribers, subscribedByProxy); + } + + private ProxySubscriber getProxySubscriber(String topic, Object subscribedByProxy) { + List subscribers = getSubscribers(topic); + return getProxySubscriber(subscribers, subscribedByProxy); + } + + private ProxySubscriber getProxySubscriber(Pattern pattern, Object subscribedByProxy) { + List subscribers = getSubscribersToPattern(pattern); + return getProxySubscriber(subscribers, subscribedByProxy); + } + + private ProxySubscriber getVetoProxySubscriber(Class eventClass, Object subscribedByProxy) { + List subscribers = getVetoSubscribers(eventClass); + return getProxySubscriber(subscribers, subscribedByProxy); + } + + private ProxySubscriber getVetoProxySubscriber(String topic, Object subscribedByProxy) { + List subscribers = getVetoSubscribers(topic); + return getProxySubscriber(subscribers, subscribedByProxy); + } + + private ProxySubscriber getVetoProxySubscriber(Pattern pattern, Object subscribedByProxy) { + List subscribers = getVetoSubscribers(pattern); + return getProxySubscriber(subscribers, subscribedByProxy); + } + + private ProxySubscriber getProxySubscriber(List subscribers, Object subscribedByProxy) { + for (Iterator iter = subscribers.iterator(); iter.hasNext();) { + Object subscriber = iter.next(); + if (subscriber instanceof WeakReference) { + WeakReference wr = (WeakReference) subscriber; + subscriber = wr.get(); + } + if (subscriber instanceof ProxySubscriber) { + ProxySubscriber proxy = (ProxySubscriber) subscriber; + subscriber = proxy.getProxiedSubscriber(); + if (subscriber == subscribedByProxy) { + return proxy; + } + } + } + return null; + } + + /** @see EventService#publish(Object) */ + public void publish(Object event) { + if (event == null) { + throw new IllegalArgumentException("Cannot publish null event."); + } + publish(event, null, null, getSubscribers(event.getClass()), getVetoSubscribers(event.getClass()), null); + } + + /** @see EventService#publish(java.lang.reflect.Type, Object) */ + public void publish(Type genericType, Object event) { + if (genericType == null) { + throw new IllegalArgumentException("genericType must not be null."); + } + if (event == null) { + throw new IllegalArgumentException("Cannot publish null event."); + } + publish(event, null, null, getSubscribers(genericType), null/*getVetoSubscribers(genericType)*/, null); + } + + /** @see EventService#publish(String,Object) */ + public void publish(String topicName, Object eventObj) { + publish(null, topicName, eventObj, getSubscribers(topicName), getVetoEventListeners(topicName), null); + } + + /** + * All publish methods call this method. Extending classes only have to override this method to handle all + * publishing cases. + * + * @param event the event to publish, null if publishing on a topic + * @param topic if publishing on a topic, the topic to publish on, else null + * @param eventObj if publishing on a topic, the eventObj to publish, else null + * @param subscribers the subscribers to publish to - must be a snapshot copy + * @param vetoSubscribers the veto subscribers to publish to - must be a snapshot copy. + * @param callingStack the stack that called this publication, helpful for reporting errors on other threads + * @throws IllegalArgumentException if eh or o is null + */ + protected void publish(final Object event, final String topic, final Object eventObj, + final List subscribers, final List vetoSubscribers, StackTraceElement[] callingStack) { + + if (event == null && topic == null) { + throw new IllegalArgumentException("Can't publish to null topic/event."); + } + + setStatus(PublicationStatus.Initiated, event, topic, eventObj); + //topic or event + logEvent(event, topic, eventObj); + + //Check all veto subscribers, if any veto, then don't publish or cache + if (checkVetoSubscribers(event, topic, eventObj, vetoSubscribers, callingStack)) { + setStatus(PublicationStatus.Vetoed, event, topic, eventObj); + return; + } else { + setStatus(PublicationStatus.Queued, event, topic, eventObj); + } + + addEventToCache(event, topic, eventObj); + + if (subscribers == null || subscribers.isEmpty()) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("No subscribers for event or topic. Event:" + event + ", Topic:" + topic); + } + } else { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Publishing to subscribers:" + subscribers); + } + setStatus(PublicationStatus.Publishing, event, topic, eventObj); + for (int i = 0; i < subscribers.size(); i++) { + Object eh = subscribers.get(i); + if (event != null) { + EventSubscriber eventSubscriber = (EventSubscriber) eh; + long start = System.currentTimeMillis(); + try { + eventSubscriber.onEvent(event); + } catch (Throwable e) { + handleException(event, e, callingStack, eventSubscriber); + } + } else { + EventTopicSubscriber eventTopicSubscriber = (EventTopicSubscriber) eh; + try { + eventTopicSubscriber.onEvent(topic, eventObj); + } catch (Throwable e) { + onEventException(topic, eventObj, e, callingStack, eventTopicSubscriber); + } + } + } + } + setStatus(PublicationStatus.Completed, event, topic, eventObj); + } + + /** + * Called during publication to set the status on an event. Can be used by subclasses + * to be notified when an event transitions from one state to another. Implementers + * are required to call setPublicationStatus + * @param status the status to set on the object + * @param event the event being published, will be null if topic is not null + * @param topic the topic eventObj is being published on, will be null if event is not null + * @param eventObj the payload being published on the topic , will be null if event is not null + */ + @SuppressWarnings({"UnusedDeclaration"}) + protected void setStatus(PublicationStatus status, Object event, String topic, Object eventObj) { + if (event instanceof PublicationStatusTracker) { + ((PublicationStatusTracker)event).setPublicationStatus(status); + } + if (eventObj instanceof PublicationStatusTracker) { + ((PublicationStatusTracker)eventObj).setPublicationStatus(status); + } + } + + /** + * Handles subscribers that are Prioritized by putting the most negative prioritized subscribers + * first, the most positive prioritized subscribers last, and leaving non-Prioritized in their + * original FIFO order. + * @param subscribers the subscribers to sort + * @return the same list if there are no prioritized subscribers in the list, otherwise a new sorted result + */ + private List sortSubscribers(List subscribers) { + if (subscribers == null) { + return null; + } + List prioritizedSubscribers = null; + Iterator iterator = subscribers.iterator(); + while (iterator.hasNext()) { + Object subscriber = iterator.next(); + if (subscriber instanceof Prioritized) { + Prioritized prioritized = ((Prioritized)subscriber); + if (prioritized.getPriority() != 0) { + iterator.remove(); + if (prioritizedSubscribers == null) { + prioritizedSubscribers = new ArrayList(); + } + prioritizedSubscribers.add(prioritized); + } + } + } + if (prioritizedSubscribers == null) { + return subscribers; + } else { + List result = new ArrayList(prioritizedSubscribers.size()+subscribers.size()); + Collections.sort(prioritizedSubscribers, PRIORITIZED_SUBSCRIBER_COMPARATOR); + boolean haveAddedFIFOSubscribers = false; + for (Prioritized prioritizedSubscriber : prioritizedSubscribers) { + if (prioritizedSubscriber.getPriority() > 0 && !haveAddedFIFOSubscribers) { + for (Object subscriber : subscribers) { + result.add(subscriber); + } + haveAddedFIFOSubscribers = true; + } + result.add(prioritizedSubscriber); + } + //Issue 26 - of all priorities are negative, then add the FIFO after processing all of them + if (!haveAddedFIFOSubscribers) { + for (Object subscriber : subscribers) { + result.add(subscriber); + } + } + return result; + } + } + + private boolean checkVetoSubscribers(Object event, String topic, Object eventObj, List vetoSubscribers, + StackTraceElement[] callingStack) { + if (vetoSubscribers != null && !vetoSubscribers.isEmpty()) { + for (Iterator vlIter = vetoSubscribers.iterator(); vlIter.hasNext();) { + Object vetoer = vlIter.next(); + VetoEventListener vl = null; + VetoTopicEventListener vtl = null; + if (event == null) { + vtl = (VetoTopicEventListener) vetoer; + } else { + vl = (VetoEventListener) vetoer; + } + long start = System.currentTimeMillis(); + try { + boolean shouldVeto = false; + if (event == null) { + shouldVeto = vtl.shouldVeto(topic, eventObj); + } else { + shouldVeto = vl.shouldVeto(event); + } + if (shouldVeto) { + handleVeto(vl, event, vtl, topic, eventObj); + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Publication vetoed. Event:" + event + ", Topic:" + topic + ", veto subscriber:" + vl); + } + return true; + } + } catch (Throwable ex) { + subscribeVetoException(event, topic, eventObj, ex, callingStack, vl); + } + } + } + return false; + } + + private void logEvent(Object event, String topic, Object eventObj) { + if (LOG.isLoggable(Level.DEBUG)) { + if (event != null) { + LOG.debug("Publishing event: class=" + event.getClass() + ", event=" + event); + } else if (topic != null) { + LOG.debug("Publishing event: topic=" + topic + ", eventObj=" + eventObj); + } + } + } + + /** + * Adds an event to the event cache, if appropriate. This method is called just before publication to listeners, + * after the event passes any veto listeners. + *

+ * Using protected visibility to open the caching to other implementations. + *

+ * + * @param event the event about to be published, null if topic is non-null + * @param topic the topic about to be published to, null if the event is non-null + * @param eventObj the eventObj about to be published on a topic, null if the event is non-null + */ + protected void addEventToCache(Object event, String topic, Object eventObj) { + //Taking the listener lock here, since a listener that is now subscribing will want + //this event since they are not in this subscriber list. + synchronized (listenerLock) { + if (event != null) { + int cacheSizeForEventClass = getCacheSizeForEventClass(event.getClass()); + List eventClassCache = (List) cacheByEvent.get(event.getClass()); + if (cacheSizeForEventClass <= 0) { + if (eventClassCache != null) { + //the cache threshold was lowered to 0 + cacheByEvent.remove(event.getClass()); + } + } else { + if (eventClassCache == null) { + eventClassCache = new LinkedList(); + cacheByEvent.put(event.getClass(), eventClassCache); + } + eventClassCache.add(0, event); + while (eventClassCache.size() > cacheSizeForEventClass) { + eventClassCache.remove(eventClassCache.size() - 1); + } + } + } else { + //topic + int cacheSizeForTopic = getCacheSizeForTopic(topic); + List topicCache = (List) cacheByTopic.get(topic); + if (cacheSizeForTopic <= 0) { + if (topicCache != null) { + //the cache threshold was lowered to 0 + topicCache.remove(topic); + } + } else { + if (topicCache == null) { + topicCache = new LinkedList(); + cacheByTopic.put(topic, topicCache); + } + topicCache.add(0, eventObj); + while (topicCache.size() > cacheSizeForTopic) { + topicCache.remove(topicCache.size() - 1); + } + } + } + } + } + + /** @see EventService#getSubscribers(Class) */ + public List getSubscribers(Class eventClass) { + List hierarchyMatches; + List exactMatches; + synchronized (listenerLock) { + hierarchyMatches = getSubscribersToClass(eventClass); + exactMatches = getSubscribersToExactClass(eventClass); + } + List result = new ArrayList(); + if (exactMatches != null) { + result.addAll(exactMatches); + } + if (hierarchyMatches != null) { + result.addAll(hierarchyMatches); + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + + } + + /** @see EventService#getSubscribersToClass(Class) */ + public List getSubscribersToClass(Class eventClass) { + synchronized (listenerLock) { + Map classMap = subscribersByEventClass; + List result = getEventOrVetoSubscribersToClass(classMap, eventClass); + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + } + + /** @see EventService#getSubscribersToExactClass(Class) */ + public List getSubscribersToExactClass(Class eventClass) { + synchronized (listenerLock) { + return getSubscribers(eventClass, subscribersByExactEventClass); + } + } + + /** @see EventService#getSubscribers(Type) */ + public List getSubscribers(Type eventType) { + List result; + synchronized (listenerLock) { + result = getEventOrVetoSubscribersToType(subscribersByEventType, eventType); + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + + /** @see EventService#getSubscribers(String) */ + public List getSubscribers(String topic) { + List result = new ArrayList(); + List exactMatches; + List patternMatches; + synchronized (listenerLock) { + exactMatches = getSubscribersToTopic(topic); + patternMatches = getSubscribersByPattern(topic); + } + if (exactMatches != null) { + result.addAll(exactMatches); + } + if (patternMatches != null) { + result.addAll(patternMatches); + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + + /** @see EventService#getSubscribersToTopic(String) */ + public List getSubscribersToTopic(String topic) { + synchronized (listenerLock) { + return getSubscribers(topic, subscribersByTopic); + } + } + + /** @see EventService#getSubscribers(Pattern) */ + public List getSubscribers(Pattern pattern) { + synchronized (listenerLock) { + return getSubscribers(pattern, subscribersByTopicPattern); + } + } + + /** @see EventService#getSubscribersByPattern(String) */ + public List getSubscribersByPattern(String topic) { + return getSubscribersByPattern(topic, subscribersByTopicPattern); + } + + /** @see EventService#getVetoSubscribers(Class) */ + public List getVetoSubscribers(Class eventClass) { + List result = new ArrayList(); + List exactMatches; + List hierarchyMatches; + synchronized (listenerLock) { + exactMatches = getVetoSubscribersToClass(eventClass); + hierarchyMatches = getVetoSubscribersToExactClass(eventClass); + } + if (exactMatches != null) { + result.addAll(exactMatches); + } + if (hierarchyMatches != null) { + result.addAll(hierarchyMatches); + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + + /** @see EventService#getVetoSubscribersToClass(Class) */ + public List getVetoSubscribersToClass(Class eventClass) { + List result; + synchronized (listenerLock) { + Map classMap = vetoListenersByClass; + result = getEventOrVetoSubscribersToClass(classMap, eventClass); + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + + /** @see EventService#getVetoSubscribersToExactClass(Class) */ + public List getVetoSubscribersToExactClass(Class eventClass) { + synchronized (listenerLock) { + return getSubscribers(eventClass, vetoListenersByExactClass); + } + } + + /** @see EventService#getVetoEventListeners(String) */ + public List getVetoEventListeners(String topicOrPattern) { + List result = new ArrayList(); + List exactMatches; + List patternMatches; + synchronized (listenerLock) { + exactMatches = getVetoSubscribersToTopic(topicOrPattern); + patternMatches = getVetoSubscribersByPattern(topicOrPattern); + } + if (exactMatches != null) { + result.addAll(exactMatches); + } + if (patternMatches != null) { + result.addAll(patternMatches); + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + + /** @see EventService#getVetoSubscribersToTopic(String) */ + public List getVetoSubscribersToTopic(String topic) { + synchronized (listenerLock) { + return getSubscribers(topic, vetoListenersByTopic); + } + } + + /** + * Note: this is inconsistent with getSubscribers(String) + * @see EventService#getVetoSubscribersToTopic(String) + * @deprecated use getVetoSubscribersToTopic instead for direct replacement, + * or use getVetoEventListeners to get topic and pattern matchers. + * In EventBus 2.0 this name will replace getVetoEventListeners() + * and have it's union functionality + */ + public List getVetoSubscribers(String topic) { + synchronized (listenerLock) { + return getVetoSubscribersToTopic(topic); + } + } + + /** @see EventService#getVetoSubscribers(Pattern) */ + public List getVetoSubscribers(Pattern topicPattern) { + synchronized (listenerLock) { + PatternWrapper patternWrapper = new PatternWrapper(topicPattern); + return getSubscribers(patternWrapper, vetoListenersByTopicPattern); + } + } + + /** @see EventService#getVetoSubscribersByPattern(String) */ + public List getVetoSubscribersByPattern(String pattern) { + return getSubscribersByPattern(pattern, vetoListenersByTopicPattern); + } + + /** Used for subscribers and veto subscribers */ + private List getSubscribersByPattern(String topic, Map subscribersByTopicPattern) { + List result = new ArrayList(); + synchronized (listenerLock) { + Set keys = subscribersByTopicPattern.keySet(); + for (Iterator iterator = keys.iterator(); iterator.hasNext();) { + PatternWrapper patternKey = (PatternWrapper) iterator.next(); + if (patternKey.matches(topic)) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Pattern " + patternKey + " matched topic name " + topic); + } + Collection subscribers = (Collection) subscribersByTopicPattern.get(patternKey); + result.addAll(createCopyOfContentsRemoveWeakRefs(subscribers)); + } + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + } + + protected List getSubscribersToPattern(Pattern topicPattern) { + synchronized (listenerLock) { + PatternWrapper patternWrapper = new PatternWrapper(topicPattern); + return getSubscribers(patternWrapper, subscribersByTopicPattern); + } + } + + private List getSubscribers(Object classOrTopic, Map subscriberMap) { + List result; + synchronized (listenerLock) { + List subscribers = (List) subscriberMap.get(classOrTopic); + //Make a defensive copy of subscribers and veto listeners so listeners + //can change the listener list while the listeners are being called + //Resolve WeakReferences and unsubscribe if necessary. + result = createCopyOfContentsRemoveWeakRefs(subscribers); + } + if (hasEverUsedPrioritized) { + result = sortSubscribers(result); + } + return result; + } + + private List getEventOrVetoSubscribersToClass(Map classMap, Class eventClass) { + List result = new ArrayList(); + Set keys = classMap.keySet(); + for (Iterator iterator = keys.iterator(); iterator.hasNext();) { + Class cl = (Class) iterator.next(); + if (cl.isAssignableFrom(eventClass)) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Hierarchical match " + cl + " matched event of class " + eventClass); + } + Collection subscribers = (Collection) classMap.get(cl); + result.addAll(createCopyOfContentsRemoveWeakRefs(subscribers)); + } + } + return result; + } + + private List getEventOrVetoSubscribersToType(Map typeMap, Type eventType) { + List result = new ArrayList(); + Set mapKeySet = typeMap.keySet(); + for (Object mapKey : mapKeySet) { + Type subscriberType = (Type) mapKey; + if (eventType instanceof ParameterizedType && subscriberType instanceof ParameterizedType) { + ParameterizedType subscriberPT = (ParameterizedType) subscriberType; + ParameterizedType eventPT = (ParameterizedType) eventType; + if (eventPT.getRawType().equals(subscriberPT.getRawType())) { + Type[] mapTypeArgs = subscriberPT.getActualTypeArguments(); + Type[] eventTypeArgs = eventPT.getActualTypeArguments(); + if (mapTypeArgs == null || eventTypeArgs == null || mapTypeArgs.length != eventTypeArgs.length) { + continue; + } + boolean parameterArgsMatch = true; + for (int argCount = 0; argCount < mapTypeArgs.length; argCount++) { + Type eventTypeArg = eventTypeArgs[argCount]; + if (eventTypeArg instanceof WildcardType) { + throw new IllegalArgumentException("Only simple Class parameterized types can be published, not wildcards, etc. Published attempt made for:"+eventTypeArg); + } + Type subscriberTypeArg = mapTypeArgs[argCount]; + if (subscriberTypeArg instanceof WildcardType) { + WildcardType wildcardSubscriberTypeArg = (WildcardType) subscriberTypeArg; + Type[] upperBound = wildcardSubscriberTypeArg.getUpperBounds(); + Type[] lowerBound = wildcardSubscriberTypeArg.getLowerBounds(); + if (upperBound != null && upperBound.length > 0) { + if (upperBound[0] instanceof Class) { + Class upper = (Class) upperBound[0]; + if (eventTypeArg instanceof Class) { + if (!upper.isAssignableFrom((Class) eventTypeArg)) { + parameterArgsMatch = false; + break; + } + } else { + parameterArgsMatch = false; + break; + } + } else { + throw new IllegalArgumentException("Only Class and Interface types are supported as types of wildcard subscriptions. Type:"+upperBound[0]); + } + } + if (lowerBound != null && lowerBound.length > 0) { + if (lowerBound[0] instanceof Class) { + Class lower = (Class) lowerBound[0]; + if (eventTypeArg instanceof Class) { + if (!((Class)eventTypeArg).isAssignableFrom(lower)) { + parameterArgsMatch = false; + break; + } + } else { + parameterArgsMatch = false; + break; + } + } else { + throw new IllegalArgumentException("Only Class and Interface types are supported as types of wildcard subscriptions. Type:"+upperBound[0]); + } + } + } else if (!subscriberTypeArg.equals(eventTypeArg)) { + parameterArgsMatch = false; + break; + } + } + if (parameterArgsMatch) { + if (LOG.isLoggable(Level.DEBUG)) { + LOG.debug("Exact parameterized subscriberType match for event subscriberType " + eventType); + } + Collection subscribers = (Collection) typeMap.get(subscriberType); + if (subscribers != null) { + result.addAll(createCopyOfContentsRemoveWeakRefs(subscribers)); + } + } + } + } + } + return result; +// Type o = p.getOwnerType(); +// if (o != null) { +// +// } +// p.getActualTypeArguments(); +// } + /* + } else if (type instanceof TypeVariable) { + TypeVariable v = (TypeVariable)type; + out.print(v.getName()); + } else if (type instanceof GenericArrayType) { + GenericArrayType a = (GenericArrayType)type; + printType(a.getGenericComponentType()); + out.print("[]"); + } else if (type instanceof WildcardType) { + WildcardType w = (WildcardType)type; + Type[] upper = w.getUpperBounds(); + Type[] lower = w.getLowerBounds(); + if (upper.length==1 && lower.length==0) { + out.print("? extends "); + printType(upper[0]); + } else if (upper.length==0 && lower.length==1) { + out.print("? super "); + printType(lower[0]); + } else assert false; + } + */ + } + + /** + * Handle vetos of an event or topic, by default logs finely. + * + * @param vl the veto listener for an event + * @param event the event, can be null if topic is not + * @param vtl the veto listener for a topic + * @param topic can be null if event is not + * @param eventObj the object published with the topic + */ + protected void handleVeto(VetoEventListener vl, Object event, + VetoTopicEventListener vtl, String topic, Object eventObj) { + if (LOG.isLoggable(Level.DEBUG)) { + if (event != null) { + LOG.debug("Vetoing event: class=" + event.getClass() + ", event=" + event + ", vetoer:" + vl); + } else { + LOG.debug("Vetoing event: topic=" + topic + ", eventObj=" + eventObj + ", vetoer:" + vtl); + } + } + } + + /** + * Given a Map (of Lists of subscribers or veto listeners), removes the toRemove element from the List in the map for + * the given key. The entire map is checked for WeakReferences and ProxySubscribers and they are all unsubscribed + * if stale. + * + * @param map map of lists + * @param key key for a List in the map + * @param toRemove the object to remove form the list with the key of the map + * + * @return true if toRemove was unsubscribed + */ + private boolean removeFromSetResolveWeakReferences(Map map, Object key, Object toRemove) { + List subscribers = (List) map.get(key); + if (subscribers == null) { + return false; + } + if (subscribers.remove(toRemove)) { + if (toRemove instanceof WeakReference) { + decWeakRefPlusProxySubscriberCount(); + } + if (toRemove instanceof ProxySubscriber) { + ((ProxySubscriber)toRemove).proxyUnsubscribed(); + decWeakRefPlusProxySubscriberCount(); + } + return true; + } + + //search for WeakReferences and ProxySubscribers + for (Iterator iter = subscribers.iterator(); iter.hasNext();) { + Object existingSubscriber = iter.next(); + if (existingSubscriber instanceof ProxySubscriber) { + ProxySubscriber proxy = (ProxySubscriber) existingSubscriber; + existingSubscriber = proxy.getProxiedSubscriber(); + if (existingSubscriber == toRemove) { + removeProxySubscriber(proxy, iter); + return true; + } + } + if (existingSubscriber instanceof WeakReference) { + WeakReference wr = (WeakReference) existingSubscriber; + Object realRef = wr.get(); + if (realRef == null) { + //clean up a garbage collected reference + iter.remove(); + decWeakRefPlusProxySubscriberCount(); + return true; + } else if (realRef == toRemove) { + iter.remove(); + decWeakRefPlusProxySubscriberCount(); + return true; + } else if (realRef instanceof ProxySubscriber) { + ProxySubscriber proxy = (ProxySubscriber) realRef; + existingSubscriber = proxy.getProxiedSubscriber(); + if (existingSubscriber == toRemove) { + removeProxySubscriber(proxy, iter); + return true; + } + } + } + } + return false; + } + + /** + * Given a set (or subscribers or veto listeners), makes a copy of the set, resolving WeakReferences to hard + * references, and removing garbage collected references from the original set. + * + * @param subscribersOrVetoListeners + * + * @return a copy of the set + */ + private List createCopyOfContentsRemoveWeakRefs(Collection subscribersOrVetoListeners) { + if (subscribersOrVetoListeners == null) { + return null; + } + List copyOfSubscribersOrVetolisteners = new ArrayList(subscribersOrVetoListeners.size()); + for (Iterator iter = subscribersOrVetoListeners.iterator(); iter.hasNext();) { + Object elem = iter.next(); + if (elem instanceof ProxySubscriber) { + ProxySubscriber proxy = (ProxySubscriber)elem; + elem = proxy.getProxiedSubscriber(); + if (elem == null) { + removeProxySubscriber(proxy, iter); + } else { + copyOfSubscribersOrVetolisteners.add(proxy); + } + } else if (elem instanceof WeakReference) { + Object hardRef = ((WeakReference) elem).get(); + if (hardRef == null) { + //Was reclaimed, unsubscribe + iter.remove(); + decWeakRefPlusProxySubscriberCount(); + } else { + copyOfSubscribersOrVetolisteners.add(hardRef); + } + } else { + copyOfSubscribersOrVetolisteners.add(elem); + } + } + return copyOfSubscribersOrVetolisteners; + } + + /** + * Sets the default cache size for each kind of event, default is 0 (no caching). + *

+ * If this value is set to a positive number, then when an event is published, the EventService caches the event or + * topic payload data for later retrieval. This allows subscribers to find out what has most recently happened + * before they subscribed. The cached event(s) are returned from #getLastEvent(Class), #getLastTopicData(String), + * #getCachedEvents(Class), or #getCachedTopicData(String) + *

+ *

+ * The default can be overridden on a by-event-class or by-topic basis. + *

+ * + * @param defaultCacheSizePerClassOrTopic + */ + public void setDefaultCacheSizePerClassOrTopic(int defaultCacheSizePerClassOrTopic) { + synchronized (cacheLock) { + this.defaultCacheSizePerClassOrTopic = defaultCacheSizePerClassOrTopic; + } + } + + /** @return the default number of event payloads kept per event class or topic */ + public int getDefaultCacheSizePerClassOrTopic() { + synchronized (cacheLock) { + return defaultCacheSizePerClassOrTopic; + } + } + + /** + * Set the number of events cached for a particular class of event. By default, no events are cached. + *

+ * This overrides any setting for the DefaultCacheSizePerClassOrTopic. + *

+ *

+ * Class hierarchy semantics are respected. That is, if there are three events, A, X and Y, and X and Y are both + * derived from A, then setting the cache size for A applies the cache size for all three. Setting the cache size + * for X applies to X and leaves the settings for A and Y in tact. Interfaces can be passed to this method, but they + * only take effect if the cache size of a class or it's superclasses has been set. Just like Class.getInterfaces(), + * if multiple cache sizes are set, the interface names declared earliest in the implements clause of the eventClass + * takes effect. + *

+ *

+ * The cache for an event is not adjusted until the next event of that class is published. + *

+ * + * @param eventClass the class of event + * @param cacheSize the number of published events to cache for this event + */ + public void setCacheSizeForEventClass(Class eventClass, int cacheSize) { + synchronized (cacheLock) { + if (rawCacheSizesForEventClass == null) { + rawCacheSizesForEventClass = new HashMap(); + } + rawCacheSizesForEventClass.put(eventClass, new Integer(cacheSize)); + rawCacheSizesForEventClassChanged = true; + } + } + + /** + * Returns the number of events cached for a particular class of event. By default, no events are cached. + *

+ * This result is computed for a particular class from the values passed to #setCacheSizeForEventClass(Class, int), + * and respects the class hierarchy. + *

+ * + * @param eventClass the class of event + * + * @return the maximum size of the event cache for the given event class + * + * @see #setCacheSizeForEventClass(Class,int) + */ + public int getCacheSizeForEventClass(Class eventClass) { + if (eventClass == null) { + throw new IllegalArgumentException("eventClass must not be null."); + } + synchronized (cacheLock) { + if (rawCacheSizesForEventClass == null || rawCacheSizesForEventClass.size() == 0) { + return getDefaultCacheSizePerClassOrTopic(); + } + if (cacheSizesForEventClass == null) { + cacheSizesForEventClass = new HashMap(); + } + if (rawCacheSizesForEventClassChanged) { + cacheSizesForEventClass.clear(); + cacheSizesForEventClass.putAll(rawCacheSizesForEventClass); + rawCacheSizesForEventClassChanged = false; + } + + //Has this been computed yet or set directly? + Integer size = (Integer) cacheSizesForEventClass.get(eventClass); + if (size != null) { + return size.intValue(); + } else { + //must be computed + Class parent = eventClass.getSuperclass(); + while (parent != null) { + Integer parentSize = (Integer) cacheSizesForEventClass.get(parent); + if (parentSize != null) { + cacheSizesForEventClass.put(eventClass, parentSize); + return parentSize.intValue(); + } + parent = parent.getSuperclass(); + } + //try interfaces + Class[] interfaces = eventClass.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + Class anInterface = interfaces[i]; + Integer interfaceSize = (Integer) cacheSizesForEventClass.get(anInterface); + if (interfaceSize != null) { + cacheSizesForEventClass.put(eventClass, interfaceSize); + return interfaceSize.intValue(); + } + } + } + return getDefaultCacheSizePerClassOrTopic(); + } + } + + /** + * Set the number of published data objects cached for a particular event topic. By default, no caching is done. + *

+ * This overrides any setting for the DefaultCacheSizePerClassOrTopic. + *

+ *

+ * Settings for exact topic names take precedence over pattern matching. + *

+ *

+ * The cache for a topic is not adjusted until the next publication on that topic. + *

+ * + * @param topicName the topic name + * @param cacheSize the number of published data Objects to cache for this topic + */ + public void setCacheSizeForTopic(String topicName, int cacheSize) { + synchronized (cacheLock) { + if (rawCacheSizesForTopic == null) { + rawCacheSizesForTopic = new HashMap(); + } + rawCacheSizesForTopic.put(topicName, new Integer(cacheSize)); + rawCacheSizesForTopicChanged = true; + } + } + + /** + * Set the number of published data objects cached for topics matching a pattern. By default, caching is done. + *

+ * This overrides any setting for the DefaultCacheSizePerClassOrTopic. + *

+ *

+ * Settings for exact topic names take precedence over pattern matching. If a topic matches the cache settings for + * more than one pattern, the cache size chosen is an undetermined one from one of the matched pattern settings. + *

+ *

+ * The cache for a topic is not adjusted until the next publication on that topic. + *

+ * + * @param pattern the pattern matching topic names + * @param cacheSize the number of data Objects to cache for this topic + */ + public void setCacheSizeForTopic(Pattern pattern, int cacheSize) { + synchronized (cacheLock) { + if (rawCacheSizesForPattern == null) { + rawCacheSizesForPattern = new HashMap(); + } + PatternWrapper patternWrapper = new PatternWrapper(pattern); + rawCacheSizesForPattern.put(patternWrapper, new Integer(cacheSize)); + rawCacheSizesForPatternChanged = true; + } + } + + /** + * Returns the number of cached data objects published on a particular topic. By default, no caching is performed. + *

+ * This result is computed for a particular topic from the values passed to #setCacheSizeForTopic(String, int) and + * #setCacheSizeForTopic(Pattern, int). + *

+ * + * @param topic the topic name + * + * @return the maximum size of the data Object cache for the given topic + * + * @see #setCacheSizeForTopic(String,int) + * @see #setCacheSizeForTopic(java.util.regex.Pattern,int) + */ + public int getCacheSizeForTopic(String topic) { + if (topic == null) { + throw new IllegalArgumentException("topic must not be null."); + } + synchronized (cacheLock) { + if ((rawCacheSizesForTopic == null || (rawCacheSizesForTopic != null && rawCacheSizesForTopic.size() == 0)) && + (rawCacheSizesForPattern == null || (rawCacheSizesForPattern != null && rawCacheSizesForPattern.size() == 0))) { + return getDefaultCacheSizePerClassOrTopic(); + } + if (cacheSizesForTopic == null) { + cacheSizesForTopic = new HashMap(); + } + if (rawCacheSizesForTopicChanged || rawCacheSizesForPatternChanged) { + cacheSizesForTopic.clear(); + cacheSizesForTopic.putAll(rawCacheSizesForTopic); + rawCacheSizesForTopicChanged = false; + rawCacheSizesForPatternChanged = false; + } + + //Is this an exact match or has it been matched to a pattern yet? + Integer size = cacheSizesForTopic.get(topic); + if (size != null) { + return size; + } else { + //try matching patterns + if (rawCacheSizesForPattern != null) { + Set patterns = rawCacheSizesForPattern.keySet(); + for (Iterator iterator = patterns.iterator(); iterator.hasNext();) { + PatternWrapper pattern = (PatternWrapper) iterator.next(); + if (pattern.matches(topic)) { + size = rawCacheSizesForPattern.get(pattern); + cacheSizesForTopic.put(topic, size); + return size; + } + } + } + } + return getDefaultCacheSizePerClassOrTopic(); + } + } + + /** + * @param eventClass an index into the cache, cannot be an interface + * + * @return the last event published for this event class, or null if caching is turned off (the default) + */ + public Object getLastEvent(Class eventClass) { + if (eventClass.isInterface()) { + throw new IllegalArgumentException("Interfaces are not accepted in get last event, use a specific event class."); + } + synchronized (cacheLock) { + List eventCache = cacheByEvent.get(eventClass); + if (eventCache == null || eventCache.size() == 0) { + return null; + } + return eventCache.get(0); + } + } + + /** + * @param eventClass an index into the cache, cannot be an interface + * + * @return the last events published for this event class, or null if caching is turned off (the default) + */ + public List getCachedEvents(Class eventClass) { + if (eventClass.isInterface()) { + throw new IllegalArgumentException("Interfaces are not accepted in get last event, use a specific event class."); + } + synchronized (cacheLock) { + List eventCache = cacheByEvent.get(eventClass); + if (eventCache == null || eventCache.size() == 0) { + return null; + } + return eventCache; + } + } + + /** + * @param topic an index into the cache + * + * @return the last data Object published on this topic, or null if caching is turned off (the default) + */ + public Object getLastTopicData(String topic) { + synchronized (cacheLock) { + List topicCache = cacheByTopic.get(topic); + if (topicCache == null || topicCache.size() == 0) { + return null; + } + return topicCache.get(0); + } + } + + /** + * @param topic an index into the cache + * + * @return the last data Objects published on this topic, or null if caching is turned off (the default) + */ + public List getCachedTopicData(String topic) { + synchronized (cacheLock) { + List topicCache = cacheByTopic.get(topic); + if (topicCache == null || topicCache.size() == 0) { + return null; + } + return topicCache; + } + } + + /** + * Clears the event cache for a specific event class or interface and it's any of it's subclasses or implementing + * classes. + * + * @param eventClassToClear the event class to clear the cache for + */ + public void clearCache(Class eventClassToClear) { + synchronized (cacheLock) { + Set classes = cacheByEvent.keySet(); + for (Iterator iterator = classes.iterator(); iterator.hasNext();) { + Class cachedClass = (Class) iterator.next(); + if (eventClassToClear.isAssignableFrom(cachedClass)) { + iterator.remove(); + } + } + } + } + + /** + * Clears the topic data cache for a specific topic name. + * + * @param topic the topic name to clear the cache for + */ + public void clearCache(String topic) { + synchronized (cacheLock) { + cacheByTopic.remove(topic); + } + } + + /** + * Clears the topic data cache for all topics that match a particular pattern. + * + * @param pattern the pattern to match topic caches to + */ + public void clearCache(Pattern pattern) { + synchronized (cacheLock) { + Set classes = cacheByTopic.keySet(); + for (Iterator iterator = classes.iterator(); iterator.hasNext();) { + String cachedTopic = (String) iterator.next(); + if (pattern.matcher(cachedTopic).matches()) { + iterator.remove(); + } + } + } + } + + /** Clear all event caches for all topics and event. */ + public void clearCache() { + synchronized (cacheLock) { + cacheByEvent.clear(); + cacheByTopic.clear(); + } + } + + /** Called during veto exceptions, calls handleException */ + protected void subscribeVetoException(final Object event, final String topic, final Object eventObj, + Throwable e, StackTraceElement[] callingStack, VetoEventListener vetoer) { + String str = "EventService veto event listener r:" + vetoer; + if (vetoer != null) { + str = str + ". Vetoer class:" + vetoer.getClass(); + } + handleException("vetoing", event, topic, eventObj, e, callingStack, str); + } + + /** Called during event handling exceptions, calls handleException */ + protected void onEventException(final String topic, final Object eventObj, Throwable e, + StackTraceElement[] callingStack, EventTopicSubscriber eventTopicSubscriber) { + String str = "EventService topic subscriber:" + eventTopicSubscriber; + if (eventTopicSubscriber != null) { + str = str + ". Subscriber class:" + eventTopicSubscriber.getClass(); + } + handleException("handling event", null, topic, eventObj, e, callingStack, str); + } + + /** Called during event handling exceptions, calls handleException */ + protected void handleException(final Object event, Throwable e, + StackTraceElement[] callingStack, EventSubscriber eventSubscriber) { + String str = "EventService subscriber:" + eventSubscriber; + if (eventSubscriber != null) { + str = str + ". Subscriber class:" + eventSubscriber.getClass(); + } + handleException("handling event topic", event, null, null, e, callingStack, str); + } + + /** + * All exception handling goes through this method. Logs a warning by default. + */ + protected void handleException(final String action, final Object event, final String topic, + final Object eventObj, Throwable e, StackTraceElement[] callingStack, String sourceString) { + String eventClassString = (event == null ? "none" : event.getClass().getName()); + String eventString = event + ""; + String contextMsg = "Exception " + action + " event class=" + eventClassString + + ", event=" + eventString + ", topic=" + topic + ", eventObj=" + eventObj; + SwingException clientEx = new SwingException(contextMsg, e, callingStack); + String msg = "Exception thrown by;" + sourceString; + LOG.log(Level.WARN, msg, clientEx); + } + + /** + * Unsubscribe a subscriber if it is a stale ProxySubscriber. Used during subscribe() and + * in the cleanup Timer. See the class javadoc. + *

+ * Not private since I don't claim I'm smart enough to anticipate all needs, but I + * am smart enough to doc the rules you must follow to override this method. Those + * rules may change (changes will be doc'ed), override at your own risk. + *

+ *

+ * Overriders MUST call iterator.remove() to unsubscribe the proxy if the subscriber is + * a ProxySubscriber and is stale and should be cleaned up. If the ProxySubscriber + * is unsubscribed, then implementers MUST also call proxyUnsubscribed() on the subscriber. + * Overriders MUST also remove the proxy from the weakProxySubscriber list by calling + * removeStaleProxyFromList. Method assumes caller is holding the listenerList + * lock (else how can you pass the iterator?). + *

+ * @param iterator current iterator + * @param existingSubscriber the current value of the iterator + * @return the real value of the param, or the proxied subscriber of the param if + * the param is a a ProxySubscriber + */ + protected Object getRealSubscriberAndCleanStaleSubscriberIfNecessary(Iterator iterator, Object existingSubscriber) { + ProxySubscriber existingProxySubscriber = null; + if (existingSubscriber instanceof WeakReference) { + existingSubscriber = ((WeakReference) existingSubscriber).get(); + if (existingSubscriber == null) { + iterator.remove(); + decWeakRefPlusProxySubscriberCount(); + } + } + if (existingSubscriber instanceof ProxySubscriber) { + existingProxySubscriber = (ProxySubscriber) existingSubscriber; + existingSubscriber = existingProxySubscriber.getProxiedSubscriber(); + if (existingProxySubscriber == null) { + removeProxySubscriber(existingProxySubscriber, iterator); + } + } + return existingSubscriber; + } + + protected void removeProxySubscriber(ProxySubscriber proxy, Iterator iter) { + iter.remove(); + proxy.proxyUnsubscribed(); + decWeakRefPlusProxySubscriberCount(); + } + + /** + * Increment the count of stale proxies and start a cleanup task if necessary + */ + protected void incWeakRefPlusProxySubscriberCount() { + synchronized(listenerLock) { + weakRefPlusProxySubscriberCount++; + if (cleanupStartThreshhold == null || cleanupPeriodMS == null) { + return; + } + if (weakRefPlusProxySubscriberCount >= cleanupStartThreshhold) { + startCleanup(); + } + } + } + + /** + * Decrement the count of stale proxies + */ + protected void decWeakRefPlusProxySubscriberCount() { + synchronized(listenerLock) { + weakRefPlusProxySubscriberCount--; + if (weakRefPlusProxySubscriberCount < 0) { + weakRefPlusProxySubscriberCount = 0; + } + } + } + + private void startCleanup() { + synchronized(listenerLock) { + if (cleanupTimer == null) { + cleanupTimer = new Timer(true); + } + if (cleanupTimerTask == null) { + cleanupTimerTask = new CleanupTimerTask(); + cleanupTimer.schedule(cleanupTimerTask, 0L, cleanupPeriodMS); + } + } + } + + class CleanupTimerTask extends TimerTask { + @Override + public void run() { + synchronized(listenerLock) { + if (weakRefPlusProxySubscriberCount <= cleanupStopThreshold) { + this.cancel(); + cleanupTimer = null; + cleanupTimerTask = null; + LOG.debug("Cancelled scheduled weak reference and proxy cleanup."); + return; + } + LOG.debug("Starting a weak reference and proxy cleanup."); + List allSubscriberMaps = new ArrayList(); + allSubscriberMaps.add(subscribersByEventType); + allSubscriberMaps.add(subscribersByEventClass); + allSubscriberMaps.add(subscribersByExactEventClass); + allSubscriberMaps.add(subscribersByTopic); + allSubscriberMaps.add(subscribersByTopicPattern); + allSubscriberMaps.add(vetoListenersByClass); + allSubscriberMaps.add(vetoListenersByExactClass); + allSubscriberMaps.add(vetoListenersByTopic); + allSubscriberMaps.add(vetoListenersByTopicPattern); + + int staleCount = 0; + for (Map subscriberMap : allSubscriberMaps) { + Set subscriptions = subscriberMap.keySet(); + for (Object subscription : subscriptions) { + List subscribers = (List) subscriberMap.get(subscription); + for (Iterator iter = subscribers.iterator(); iter.hasNext();) { + Object subscriber = iter.next(); + Object realSubscriber = getRealSubscriberAndCleanStaleSubscriberIfNecessary(iter, subscriber); + if (realSubscriber == null) { + staleCount++; + } + } + } + } + } + } + } + + private static class PrioritizedSubscriberComparator implements Comparator { + public int compare(Prioritized prioritized1, Prioritized prioritized2) { + if (prioritized1 == null) { + return -1; + } + if (prioritized2 == null) { + return 1; + } + if (prioritized1.getPriority() < prioritized2.getPriority()) { + return -1; + } else if (prioritized1.getPriority() > prioritized2.getPriority()) { + return 1; + } else { + return 0; + } + } + } + + /** + * Since Pattern doesn't implement equals(), we need one of these + */ + private class PatternWrapper { + private Pattern pattern; + + public PatternWrapper(Pattern pat) { + pattern = pat; + } + + public boolean matches(CharSequence input) { + return pattern.matcher(input).matches(); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PatternWrapper that = (PatternWrapper) o; + + if (pattern != null) { + if (!pattern.equals(that.pattern)) {//give the JVM a shot for forward compatibility + return pattern.pattern() != null && this.pattern.pattern().equals(this.pattern.pattern()); + } + } else { + if (that.pattern != null) { + return false; + } + } + + return true; + } + + public int hashCode() { + if (this.pattern != null && this.pattern.pattern() != null) { + return this.pattern.pattern().hashCode(); + } + return (pattern != null ? pattern.hashCode() : 0); + } + } +} diff --git a/src/main/java/org/scijava/event/bushe/TypeReference.java b/src/main/java/org/scijava/event/bushe/TypeReference.java new file mode 100644 index 000000000..06ff73a8c --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/TypeReference.java @@ -0,0 +1,52 @@ +package org.scijava.event.bushe; + +import java.lang.reflect.Type; +import java.lang.reflect.Constructor; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.InvocationTargetException; + +/** + * Courtesy of Neil Gafter's blog. + * Thanks to Curt Cox for the pointer. + */ +abstract class TypeReference { + + private final Type type; + private volatile Constructor constructor; + + protected TypeReference() { + Type superclass = getClass().getGenericSuperclass(); + if (superclass instanceof Class) { + throw new RuntimeException("Missing type parameter."); + } + this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; + } + + /** + * @return a new instance of {@code T} using the default, no-arg + * constructor. + * @throws IllegalAccessException on security reflection issues + * @throws NoSuchMethodException there's not getRawType on the type + * @throws java.lang.reflect.InvocationTargetException if a reflective call causes an exception in the underlying instance + * @throws InstantiationException if the instance cannot be instantiated + */ + @SuppressWarnings("unchecked") + public T newInstance() + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException, InstantiationException { + if (constructor == null) { + Class rawType = type instanceof Class + ? (Class) type + : (Class) ((ParameterizedType) type).getRawType(); + constructor = rawType.getConstructor(); + } + return (T) constructor.newInstance(); + } + + /** + * @return the referenced type. + */ + public Type getType() { + return this.type; + } +} diff --git a/src/main/java/org/scijava/event/bushe/VetoEventListener.java b/src/main/java/org/scijava/event/bushe/VetoEventListener.java new file mode 100644 index 000000000..4b377c1c1 --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/VetoEventListener.java @@ -0,0 +1,39 @@ +/** + * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com + * + * Licensed 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.scijava.event.bushe; + +/** + * Interface for classes that can veto class-based event publication from the {@link EventService}. + * + * @author Michael Bushe michael@bushe.com + */ +interface VetoEventListener { + + /** + * Determine whether an event should be vetoed or published. + *

+ * The EventService calls this method before class-based publication of objects. If any of the + * VetoEventListeners return true, then none of the subscribers for that event are called.

Prerequisite: + * VetoEventListener has to be subscribed with the EventService for the event object's class.

Guaranteed to be + * called in the SwingEventThread when using the SwingEventService (EventBus). See {@link EventService}

+ *

+ * + * @param event The event object to veto or allow to be published. + * + * @return true if the event should be vetoed and not published, false if the event should be published. + */ + public boolean shouldVeto(T event); +} diff --git a/src/main/java/org/scijava/event/bushe/VetoTopicEventListener.java b/src/main/java/org/scijava/event/bushe/VetoTopicEventListener.java new file mode 100644 index 000000000..f44d9693a --- /dev/null +++ b/src/main/java/org/scijava/event/bushe/VetoTopicEventListener.java @@ -0,0 +1,26 @@ +package org.scijava.event.bushe; + +/** + * Interface for classes that can veto publication on topic names from the {@link org.scijava.event.bushe.EventService}. + * + * @author Michael Bushe michael@bushe.com + */ +interface VetoTopicEventListener { + + /** + * Determine whether a topic publication should be vetoed or allowed. + *

+ * The EventService calls this method before publication of on a topic name. If any of the + * VetoTopicEventListeners return true, then none of the subscribers to that topic are called.

Prerequisite: + * VetoTopicEventListener has to be subscribed with the EventService for the topic name.

Guaranteed to be + * called in the SwingEventThread when using the SwingEventService (EventBus). See {@link EventService}

+ *

+ * + * @param topic The topic name the data object is published on. + * @param data The data object being published on the topic. + * + * @return true if the publication on the topic should be vetoed and not published, false if the data should be + * published on the topic. + */ + public boolean shouldVeto(String topic, T data); +} diff --git a/src/main/java/org/scijava/input/Accelerator.java b/src/main/java/org/scijava/input/Accelerator.java index 4615ffd21..73878ca15 100644 --- a/src/main/java/org/scijava/input/Accelerator.java +++ b/src/main/java/org/scijava/input/Accelerator.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/input/DefaultInputService.java b/src/main/java/org/scijava/input/DefaultInputService.java index b31364f48..392dc250d 100644 --- a/src/main/java/org/scijava/input/DefaultInputService.java +++ b/src/main/java/org/scijava/input/DefaultInputService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/input/InputModifiers.java b/src/main/java/org/scijava/input/InputModifiers.java index 51dca592c..50dba7820 100644 --- a/src/main/java/org/scijava/input/InputModifiers.java +++ b/src/main/java/org/scijava/input/InputModifiers.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/input/InputService.java b/src/main/java/org/scijava/input/InputService.java index 5966c06d7..0c7adae95 100644 --- a/src/main/java/org/scijava/input/InputService.java +++ b/src/main/java/org/scijava/input/InputService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/input/KeyCode.java b/src/main/java/org/scijava/input/KeyCode.java index e09a75dd5..a8eeccaad 100644 --- a/src/main/java/org/scijava/input/KeyCode.java +++ b/src/main/java/org/scijava/input/KeyCode.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -52,7 +52,7 @@ public enum KeyCode { CANCEL(0x03), /** Clear. */ - CLEAR(0x0C), + CLEAR(0x0c), /** Shift (left or right). */ SHIFT(0x10), @@ -70,7 +70,7 @@ public enum KeyCode { CAPS_LOCK(0x14), /** Escape. */ - ESCAPE(0x1B), + ESCAPE(0x1b), /** Space (' '). */ SPACE(0x20), @@ -100,16 +100,16 @@ public enum KeyCode { DOWN(0x28), /** Comma (','). */ - COMMA(0x2C), + COMMA(0x2c), /** Minus ('-'). */ - MINUS(0x2D), + MINUS(0x2d), /** Period ('.'). */ - PERIOD(0x2E), + PERIOD(0x2e), /** Forward slash ('/'). */ - SLASH(0x2F), + SLASH(0x2f), /** Zero ('0', non-numpad). */ NUM0(0x30), @@ -142,10 +142,10 @@ public enum KeyCode { NUM9(0x39), /** Semicolon (';'). */ - SEMICOLON(0x3B), + SEMICOLON(0x3b), /** Equals ('='). */ - EQUALS(0x3D), + EQUALS(0x3d), /** The letter A. */ A(0x41), @@ -175,22 +175,22 @@ public enum KeyCode { I(0x49), /** The letter J. */ - J(0x4A), + J(0x4a), /** The letter K. */ - K(0x4B), + K(0x4b), /** The letter L. */ - L(0x4C), + L(0x4c), /** The letter M. */ - M(0x4D), + M(0x4d), /** The letter N. */ - N(0x4E), + N(0x4e), /** The letter O. */ - O(0x4F), + O(0x4f), /** The letter P. */ P(0x50), @@ -223,16 +223,16 @@ public enum KeyCode { Y(0x59), /** The letter Z. */ - Z(0x5A), + Z(0x5a), /** Left bracket ('['). */ - OPEN_BRACKET(0x5B), + OPEN_BRACKET(0x5b), /** Backslash ('\\'). */ - BACK_SLASH(0x5C), + BACK_SLASH(0x5c), /** Right bracket (']'). */ - CLOSE_BRACKET(0x5D), + CLOSE_BRACKET(0x5d), /** Zero ('0') on numeric keypad. */ NUMPAD_0(0x60), @@ -265,24 +265,24 @@ public enum KeyCode { NUMPAD_9(0x69), /** Asterisk ('*') on numeric keypad. */ - NUMPAD_ASTERISK(0x6A), + NUMPAD_ASTERISK(0x6a), /** Plus ('+') on numeric keypad. */ - NUMPAD_PLUS(0x6B), + NUMPAD_PLUS(0x6b), - NUMPAD_SEPARATOR(0x6C), + NUMPAD_SEPARATOR(0x6c), /** Minus ('-') on numeric keypad. */ - NUMPAD_MINUS(0x6D), + NUMPAD_MINUS(0x6d), /** Period ('.') on numeric keypad. */ - NUMPAD_PERIOD(0x6E), + NUMPAD_PERIOD(0x6e), /** Slash ('/') on numeric keypad. */ - NUMPAD_SLASH(0x6F), + NUMPAD_SLASH(0x6f), /** Delete (non-numpad). */ - DELETE(0x7F), + DELETE(0x7f), /** Num Lock. */ NUM_LOCK(0x90), @@ -321,76 +321,76 @@ public enum KeyCode { F10(0x79), /** F11. */ - F11(0x7A), + F11(0x7a), /** F12. */ - F12(0x7B), + F12(0x7b), /** F13. */ - F13(0xF000), + F13(0xf000), /** F14. */ - F14(0xF001), + F14(0xf001), /** F15. */ - F15(0xF002), + F15(0xf002), /** F16. */ - F16(0xF003), + F16(0xf003), /** F17. */ - F17(0xF004), + F17(0xf004), /** F18 */ - F18(0xF005), + F18(0xf005), /** F19. */ - F19(0xF006), + F19(0xf006), /** F20. */ - F20(0xF007), + F20(0xf007), /** F21. */ - F21(0xF008), + F21(0xf008), /** F22. */ - F22(0xF009), + F22(0xf009), /** F23. */ - F23(0xF00A), + F23(0xf00a), /** F24. */ - F24(0xF00B), + F24(0xf00b), /** Print Screen. */ - PRINTSCREEN(0x9A), + PRINTSCREEN(0x9a), /** Insert. */ - INSERT(0x9B), + INSERT(0x9b), /** Help. */ - HELP(0x9C), + HELP(0x9c), /** Meta. */ - META(0x9D), + META(0x9d), /** Backquote ('`'). */ - BACK_QUOTE(0xC0), + BACK_QUOTE(0xc0), /** Single quote ('\''). */ - QUOTE(0xDE), + QUOTE(0xde), /** Up arrow on numeric keypad. */ - KP_UP(0xE0), + KP_UP(0xe0), /** Down arrow on numeric keypad. */ - KP_DOWN(0xE1), + KP_DOWN(0xe1), /** Left arrow on numeric keypad. */ - KP_LEFT(0xE2), + KP_LEFT(0xe2), /** Right arrow on numeric keypad. */ - KP_RIGHT(0xE3), + KP_RIGHT(0xe3), /** TODO. */ DEAD_GRAVE(0x80), @@ -492,51 +492,51 @@ public enum KeyCode { PLUS(0x0209), /** Right parenthesis (')'). */ - RIGHT_PARENTHESIS(0x020A), + RIGHT_PARENTHESIS(0x020a), /** Underscore ('_'). */ - UNDERSCORE(0x020B), + UNDERSCORE(0x020b), /** Windows key (both left and right). */ - WINDOWS(0x020C), + WINDOWS(0x020c), /** Windows Context Menu key. */ - CONTEXT_MENU(0x020D), + CONTEXT_MENU(0x020d), FINAL(0x0018), /** Convert function key. */ - CONVERT(0x001C), + CONVERT(0x001c), /** Don't Convert function key. */ - NONCONVERT(0x001D), + NONCONVERT(0x001d), /** Accept or Commit function key. */ - ACCEPT(0x001E), + ACCEPT(0x001e), - MODECHANGE(0x001F), + MODECHANGE(0x001f), KANA(0x0015), KANJI(0x0019), /** Alphanumeric function key. */ - ALPHANUMERIC(0x00F0), + ALPHANUMERIC(0x00f0), /** Katakana function key. */ - KATAKANA(0x00F1), + KATAKANA(0x00f1), /** Hiragana function key. */ - HIRAGANA(0x00F2), + HIRAGANA(0x00f2), /** Full-Width Characters function key. */ - FULL_WIDTH(0x00F3), + FULL_WIDTH(0x00f3), /** Half-Width Characters function key. */ - HALF_WIDTH(0x00F4), + HALF_WIDTH(0x00f4), /** Roman Characters function key. */ - ROMAN_CHARACTERS(0x00F5), + ROMAN_CHARACTERS(0x00f5), /** All Candidates function key. */ ALL_CANDIDATES(0x0100), @@ -563,37 +563,37 @@ public enum KeyCode { INPUT_METHOD_ON_OFF(0x0107), /** Cut (Sun keyboard). */ - CUT(0xFFD1), + CUT(0xffd1), /** Copy (Sun keyboard). */ - COPY(0xFFCD), + COPY(0xffcd), /** Paste (Sun keyboard). */ - PASTE(0xFFCF), + PASTE(0xffcf), /** Undo (Sun keyboard). */ - UNDO(0xFFCB), + UNDO(0xffcb), /** Again (Sun keyboard). */ - AGAIN(0xFFC9), + AGAIN(0xffc9), /** Find (Sun keyboard). */ - FIND(0xFFD0), + FIND(0xffd0), /** Props (Sun keyboard). */ - PROPS(0xFFCA), + PROPS(0xffca), /** Stop (Sun keyboard). */ - STOP(0xFFC8), + STOP(0xffc8), /** Compose function key. */ - COMPOSE(0xFF20), + COMPOSE(0xff20), /** AltGraph function key. */ - ALT_GRAPH(0xFF7E), + ALT_GRAPH(0xff7e), /** Begin key. */ - BEGIN(0xFF58), + BEGIN(0xff58), /** Unknown code. */ UNDEFINED(0x0); @@ -632,14 +632,97 @@ public static KeyCode get(final int code) { return keyCode; } + /** + * Gets the KeyCode corresponding to the given character, + * or {@link #UNDEFINED} if no such code. + */ + public static KeyCode get(final char c) { + switch (c) { + case '\n': case '\r': return ENTER; + case '\b': return BACK_SPACE; + case '\t': return TAB; + case 0x1b: return ESCAPE; + case ' ': return SPACE; + case ',': return COMMA; + case '-': return MINUS; + case '.': return PERIOD; + case '/': return SLASH; + case '0': return NUM0; + case '1': return NUM1; + case '2': return NUM2; + case '3': return NUM3; + case '4': return NUM4; + case '5': return NUM5; + case '6': return NUM6; + case '7': return NUM7; + case '8': return NUM8; + case '9': return NUM9; + case ';': return SEMICOLON; + case '=': return EQUALS; + case 'a': case 'A': return A; + case 'b': case 'B': return B; + case 'c': case 'C': return C; + case 'd': case 'D': return D; + case 'e': case 'E': return E; + case 'f': case 'F': return F; + case 'g': case 'G': return G; + case 'h': case 'H': return H; + case 'i': case 'I': return I; + case 'j': case 'J': return J; + case 'k': case 'K': return K; + case 'l': case 'L': return L; + case 'm': case 'M': return M; + case 'n': case 'N': return N; + case 'o': case 'O': return O; + case 'p': case 'P': return P; + case 'q': case 'Q': return Q; + case 'r': case 'R': return R; + case 's': case 'S': return S; + case 't': case 'T': return T; + case 'u': case 'U': return U; + case 'v': case 'V': return V; + case 'w': case 'W': return W; + case 'x': case 'X': return X; + case 'y': case 'Y': return Y; + case 'z': case 'Z': return Z; + case '[': return OPEN_BRACKET; + case '\\': return BACK_SLASH; + case ']': return CLOSE_BRACKET; + case '`': return BACK_QUOTE; + case '\'': return QUOTE; + case '&': return AMPERSAND; + case '*': return ASTERISK; + case '"': return QUOTEDBL; + case '<': return LESS; + case '>': return GREATER; + case '{': return BRACELEFT; + case '}': return BRACERIGHT; + case '@': return AT; + case ':': return COLON; + case '^': return CIRCUMFLEX; + case '$': return DOLLAR; + case '€': return EURO_SIGN; + case '!': return EXCLAMATION_MARK; + case 161: return INVERTED_EXCLAMATION_MARK; + case '(': return LEFT_PARENTHESIS; + case '#': return NUMBER_SIGN; + case '+': return PLUS; + case ')': return RIGHT_PARENTHESIS; + case '_': return UNDERSCORE; + } + return UNDEFINED; + } + /** * Gets the KeyCode with the given name, or {@link #UNDEFINED} if no such * code. */ public static KeyCode get(final String name) { final KeyCode keyCode = NAMES.get(name); - if (keyCode == null) return UNDEFINED; - return keyCode; + if (keyCode != null) return keyCode; + // Not a code name, but maybe a direct character value? + if (name.length() == 1) return KeyCode.get(name.charAt(0)); + return UNDEFINED; } } diff --git a/src/main/java/org/scijava/input/MouseCursor.java b/src/main/java/org/scijava/input/MouseCursor.java index e04d7d9da..15bb0ccc8 100644 --- a/src/main/java/org/scijava/input/MouseCursor.java +++ b/src/main/java/org/scijava/input/MouseCursor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/AbstractIOPlugin.java b/src/main/java/org/scijava/io/AbstractIOPlugin.java index 787879832..3c965739a 100644 --- a/src/main/java/org/scijava/io/AbstractIOPlugin.java +++ b/src/main/java/org/scijava/io/AbstractIOPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/AbstractTypedIOService.java b/src/main/java/org/scijava/io/AbstractTypedIOService.java index 4ca97bd1b..4d75bfb3e 100644 --- a/src/main/java/org/scijava/io/AbstractTypedIOService.java +++ b/src/main/java/org/scijava/io/AbstractTypedIOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/ByteArrayByteBank.java b/src/main/java/org/scijava/io/ByteArrayByteBank.java index e3b833405..f0183f2d8 100644 --- a/src/main/java/org/scijava/io/ByteArrayByteBank.java +++ b/src/main/java/org/scijava/io/ByteArrayByteBank.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/ByteBank.java b/src/main/java/org/scijava/io/ByteBank.java index c79cbd5d4..8d466e8ce 100644 --- a/src/main/java/org/scijava/io/ByteBank.java +++ b/src/main/java/org/scijava/io/ByteBank.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/DefaultIOService.java b/src/main/java/org/scijava/io/DefaultIOService.java index b59d2113d..0b67ce690 100644 --- a/src/main/java/org/scijava/io/DefaultIOService.java +++ b/src/main/java/org/scijava/io/DefaultIOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -61,6 +61,24 @@ public final class DefaultIOService @Parameter private LocationService locationService; + + @Override + public IOPlugin getOpener(final String source) throws IOException { + try { + return getOpener(locationService.resolve(source)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + + @Override + public IOPlugin getSaver(D data, String destination) throws IOException { + try { + return getSaver(data, locationService.resolve(destination)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } @Override public Object open(final String source) throws IOException { @@ -112,4 +130,5 @@ public void save(final Object data, final Location destination) log.error("No Saver IOPlugin found for " + data.toString() + "."); } } + } diff --git a/src/main/java/org/scijava/io/DefaultRecentFileService.java b/src/main/java/org/scijava/io/DefaultRecentFileService.java index 050b22e78..3cef6fb1a 100644 --- a/src/main/java/org/scijava/io/DefaultRecentFileService.java +++ b/src/main/java/org/scijava/io/DefaultRecentFileService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/IOPlugin.java b/src/main/java/org/scijava/io/IOPlugin.java index 118b693e2..b8c69cc18 100644 --- a/src/main/java/org/scijava/io/IOPlugin.java +++ b/src/main/java/org/scijava/io/IOPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,9 +30,10 @@ package org.scijava.io; import java.io.IOException; +import java.net.URISyntaxException; -import org.scijava.io.location.FileLocation; import org.scijava.io.location.Location; +import org.scijava.io.location.LocationService; import org.scijava.plugin.HandlerPlugin; import org.scijava.plugin.Plugin; @@ -56,24 +57,34 @@ public interface IOPlugin extends HandlerPlugin { Class getDataType(); /** Checks whether the I/O plugin can open data from the given source. */ - @SuppressWarnings("unused") default boolean supportsOpen(final String source) { - return supportsOpen(new FileLocation(source)); + try { + return supportsOpen(context().service(LocationService.class).resolve(source)); + } + catch (final URISyntaxException exc) { + return false; + } } /** Checks whether the I/O plugin can open data from the given location. */ - default boolean supportsOpen(Location source) { + @SuppressWarnings("unused") + default boolean supportsOpen(final Location source) { return false; } /** Checks whether the I/O plugin can save data to the given destination. */ - @SuppressWarnings("unused") default boolean supportsSave(final String destination) { - return supportsSave(new FileLocation(destination)); + try { + return supportsSave(context().service(LocationService.class).resolve(destination)); + } + catch (final URISyntaxException exc) { + return false; + } } /** Checks whether the I/O plugin can save data to the given location. */ - default boolean supportsSave(Location destination) { + @SuppressWarnings("unused") + default boolean supportsSave(final Location destination) { return false; } @@ -85,7 +96,7 @@ default boolean supportsSave(final Object data, final String destination) { return supportsSave(destination) && getDataType().isInstance(data); } - default boolean supportsSave(Object data, Location destination) { + default boolean supportsSave(final Object data, final Location destination) { return supportsSave(destination) && getDataType().isInstance(data); } @@ -96,17 +107,24 @@ default D open(final String source) throws IOException { } /** Opens data from the given location. */ - default D open(Location source) throws IOException { + @SuppressWarnings("unused") + default D open(final Location source) throws IOException { throw new UnsupportedOperationException(); } + /** Saves the given data to the specified destination. */ - @SuppressWarnings("unused") default void save(final D data, final String destination) throws IOException { - save(data, new FileLocation(destination)); + try { + save(data, context().service(LocationService.class).resolve(destination)); + } + catch (final URISyntaxException exc) { + throw new UnsupportedOperationException(exc); + } } /** Saves the given data to the specified location. */ - default void save(D data, Location destination) throws IOException { + @SuppressWarnings("unused") + default void save(final D data, final Location destination) throws IOException { throw new UnsupportedOperationException(); } diff --git a/src/main/java/org/scijava/io/IOService.java b/src/main/java/org/scijava/io/IOService.java index 499e18ea5..672ba9f9b 100644 --- a/src/main/java/org/scijava/io/IOService.java +++ b/src/main/java/org/scijava/io/IOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,7 +31,6 @@ import java.io.IOException; -import org.scijava.io.location.FileLocation; import org.scijava.io.location.Location; import org.scijava.plugin.HandlerService; import org.scijava.service.SciJavaService; @@ -49,9 +48,7 @@ public interface IOService extends HandlerService>, * Gets the most appropriate {@link IOPlugin} for opening data from the given * location. */ - default IOPlugin getOpener(final String source) { - return getOpener(new FileLocation(source)); - } + IOPlugin getOpener(final String source) throws IOException; /** * Gets the most appropriate {@link IOPlugin} for opening data from the given @@ -68,9 +65,7 @@ default IOPlugin getOpener(Location source) { * Gets the most appropriate {@link IOPlugin} for saving data to the given * location. */ - default IOPlugin getSaver(final D data, final String destination) { - return getSaver(data, new FileLocation(destination)); - } + IOPlugin getSaver(final D data, final String destination) throws IOException; /** * Gets the most appropriate {@link IOPlugin} for saving data to the given diff --git a/src/main/java/org/scijava/io/RecentFileService.java b/src/main/java/org/scijava/io/RecentFileService.java index 019d0a6a1..20a6ad9c8 100644 --- a/src/main/java/org/scijava/io/RecentFileService.java +++ b/src/main/java/org/scijava/io/RecentFileService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/TypedIOService.java b/src/main/java/org/scijava/io/TypedIOService.java index 0439544e8..e6882fc95 100644 --- a/src/main/java/org/scijava/io/TypedIOService.java +++ b/src/main/java/org/scijava/io/TypedIOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,9 +30,11 @@ package org.scijava.io; import java.io.IOException; +import java.net.URISyntaxException; import org.scijava.io.location.FileLocation; import org.scijava.io.location.Location; +import org.scijava.io.location.LocationService; import org.scijava.plugin.HandlerService; import org.scijava.service.SciJavaService; @@ -51,7 +53,12 @@ public interface TypedIOService extends HandlerService> * location. */ default IOPlugin getOpener(final String source) { - return getOpener(new FileLocation(source)); + try { + return getOpener(context().service(LocationService.class).resolve(source)); + } + catch (final URISyntaxException exc) { + return null; + } } /** @@ -70,7 +77,12 @@ default IOPlugin getOpener(Location source) { * location. */ default IOPlugin getSaver(final D data, final String destination) { - return getSaver(data, new FileLocation(destination)); + try { + return getSaver(data, context().service(LocationService.class).resolve(destination)); + } + catch (final URISyntaxException exc) { + return null; + } } /** diff --git a/src/main/java/org/scijava/io/console/OpenArgument.java b/src/main/java/org/scijava/io/console/OpenArgument.java index a198a946e..bfdc3dbdd 100644 --- a/src/main/java/org/scijava/io/console/OpenArgument.java +++ b/src/main/java/org/scijava/io/console/OpenArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/event/DataOpenedEvent.java b/src/main/java/org/scijava/io/event/DataOpenedEvent.java index a13d20c18..c177c9195 100644 --- a/src/main/java/org/scijava/io/event/DataOpenedEvent.java +++ b/src/main/java/org/scijava/io/event/DataOpenedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -49,7 +49,7 @@ public DataOpenedEvent(final Location location, final Object data) { */ @Deprecated public DataOpenedEvent(final String source, final Object data) { - this(new FileLocation(source), data); + super(source, data); } /** @@ -57,12 +57,6 @@ public DataOpenedEvent(final String source, final Object data) { */ @Deprecated public String getSource() { - try { - FileLocation fileLocation = (FileLocation) getLocation(); - return fileLocation.getFile().getAbsolutePath(); - } catch(ClassCastException e) { - return getLocation().getURI().toString(); - } + return getDescriptor(); } - } diff --git a/src/main/java/org/scijava/io/event/DataSavedEvent.java b/src/main/java/org/scijava/io/event/DataSavedEvent.java index 427da0e6a..ec75495c9 100644 --- a/src/main/java/org/scijava/io/event/DataSavedEvent.java +++ b/src/main/java/org/scijava/io/event/DataSavedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -49,7 +49,7 @@ public DataSavedEvent(final Location destination, final Object data) { */ @Deprecated public DataSavedEvent(final String destination, final Object data) { - this(new FileLocation(destination), data); + super(destination, data); } /** @@ -57,11 +57,6 @@ public DataSavedEvent(final String destination, final Object data) { */ @Deprecated public String getDestination() { - try { - FileLocation fileLocation = (FileLocation) getLocation(); - return fileLocation.getFile().getAbsolutePath(); - } catch(ClassCastException e) { - return getLocation().getURI().toString(); - } + return getDescriptor(); } } diff --git a/src/main/java/org/scijava/io/event/IOEvent.java b/src/main/java/org/scijava/io/event/IOEvent.java index f3ff1652a..20a28a191 100644 --- a/src/main/java/org/scijava/io/event/IOEvent.java +++ b/src/main/java/org/scijava/io/event/IOEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,9 +29,12 @@ package org.scijava.io.event; +import java.net.URISyntaxException; + import org.scijava.event.SciJavaEvent; import org.scijava.io.location.FileLocation; import org.scijava.io.location.Location; +import org.scijava.io.location.LocationService; /** * An event indicating that I/O (e.g., opening or saving) has occurred. @@ -43,6 +46,10 @@ public abstract class IOEvent extends SciJavaEvent { /** The data location (source or destination). */ private final Location location; + /** @deprecated use {@link #location} instead */ + @Deprecated + private final String descriptor; + /** The data for which I/O took place. */ private final Object data; @@ -51,17 +58,26 @@ public abstract class IOEvent extends SciJavaEvent { */ @Deprecated public IOEvent(final String descriptor, final Object data) { - this(new FileLocation(descriptor), data); + this.location = null; + this.descriptor = descriptor; + this.data = data; } public IOEvent(final Location location, final Object data) { this.location = location; + this.descriptor = null; this.data = data; } /** Gets the data location (source or destination). */ public Location getLocation() { - return location; + if (location != null) return location; + try { + return context().service(LocationService.class).resolve(descriptor); + } + catch (final URISyntaxException exc) { + return null; + } } /** Gets the data for which I/O took place. */ @@ -82,12 +98,11 @@ public String toString() { */ @Deprecated public String getDescriptor() { - try { - FileLocation fileLocation = (FileLocation) getLocation(); + if (descriptor != null) return descriptor; + if (location instanceof FileLocation) { + final FileLocation fileLocation = (FileLocation) location; return fileLocation.getFile().getAbsolutePath(); - } catch(ClassCastException e) { - return getLocation().getURI().toString(); } + return location.getURI().toString(); } - } diff --git a/src/main/java/org/scijava/io/handle/AbstractDataHandle.java b/src/main/java/org/scijava/io/handle/AbstractDataHandle.java index c9007e250..f2446f90a 100644 --- a/src/main/java/org/scijava/io/handle/AbstractDataHandle.java +++ b/src/main/java/org/scijava/io/handle/AbstractDataHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java b/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java index fb191561c..7fa3d8df9 100644 --- a/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java +++ b/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java b/src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java index 838cc9229..5b56c5e93 100644 --- a/src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java +++ b/src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/AbstractStreamHandle.java b/src/main/java/org/scijava/io/handle/AbstractStreamHandle.java index 3c86730a8..75a9f4939 100644 --- a/src/main/java/org/scijava/io/handle/AbstractStreamHandle.java +++ b/src/main/java/org/scijava/io/handle/AbstractStreamHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/BytesHandle.java b/src/main/java/org/scijava/io/handle/BytesHandle.java index c967b1380..b09228673 100644 --- a/src/main/java/org/scijava/io/handle/BytesHandle.java +++ b/src/main/java/org/scijava/io/handle/BytesHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -48,6 +48,14 @@ public class BytesHandle extends AbstractDataHandle { private long offset = 0; + // -- Constructors -- + + public BytesHandle() { } + + public BytesHandle(final BytesLocation location) { + set(location); + } + // -- DataHandle methods -- @Override diff --git a/src/main/java/org/scijava/io/handle/DataHandle.java b/src/main/java/org/scijava/io/handle/DataHandle.java index 7be53f5bb..18cddadcb 100644 --- a/src/main/java/org/scijava/io/handle/DataHandle.java +++ b/src/main/java/org/scijava/io/handle/DataHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/DataHandleInputStream.java b/src/main/java/org/scijava/io/handle/DataHandleInputStream.java index 92e72dcab..10e6b84e9 100644 --- a/src/main/java/org/scijava/io/handle/DataHandleInputStream.java +++ b/src/main/java/org/scijava/io/handle/DataHandleInputStream.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/DataHandleOutputStream.java b/src/main/java/org/scijava/io/handle/DataHandleOutputStream.java index 6b30e1c59..3328a4e0a 100644 --- a/src/main/java/org/scijava/io/handle/DataHandleOutputStream.java +++ b/src/main/java/org/scijava/io/handle/DataHandleOutputStream.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/DataHandleService.java b/src/main/java/org/scijava/io/handle/DataHandleService.java index dfb5007f4..fae0e7f4a 100644 --- a/src/main/java/org/scijava/io/handle/DataHandleService.java +++ b/src/main/java/org/scijava/io/handle/DataHandleService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/DataHandles.java b/src/main/java/org/scijava/io/handle/DataHandles.java index 0ed55abc0..1464f637e 100644 --- a/src/main/java/org/scijava/io/handle/DataHandles.java +++ b/src/main/java/org/scijava/io/handle/DataHandles.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,10 +30,8 @@ package org.scijava.io.handle; import java.io.DataOutput; -import java.io.DataOutputStream; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import java.io.UTFDataFormatException; import org.scijava.io.location.Location; import org.scijava.task.Task; @@ -46,8 +44,6 @@ */ public final class DataHandles { - private static Method utfMethod; - private DataHandles() { // Prevent instantiation of utility class. } @@ -74,40 +70,38 @@ private DataHandles() { public static int writeUTF(final String str, final DataOutput out) throws IOException { - // HACK: Strangely, DataOutputStream.writeUTF(String, DataOutput) - // has package-private access. We work around it via reflection. - try { - return (Integer) utfMethod().invoke(null, str, out); - } - catch (final IllegalAccessException | IllegalArgumentException - | InvocationTargetException exc) - { - throw new IllegalStateException( - "Cannot invoke DataOutputStream.writeUTF(String, DataOutput)", exc); + // Encode string as modified UTF-8 per java.io.DataOutput specification. + final int strlen = str.length(); + int utflen = 0; + for (int i = 0; i < strlen; i++) { + final char c = str.charAt(i); + if (c >= '\u0001' && c <= '\u007F') utflen += 1; + else if (c <= '\u07FF') utflen += 2; + else utflen += 3; } - } - - // -- Helper methods -- - - /** Gets the {@link #utfMethod} field, initializing if needed. */ - private static Method utfMethod() { - if (utfMethod == null) initUTFMethod(); - return utfMethod; - } - - /** Initializes the {@link #utfMethod} field. */ - private static synchronized void initUTFMethod() { - if (utfMethod != null) return; - try { - final Method m = DataOutputStream.class.getDeclaredMethod("writeUTF", - String.class, DataOutput.class); - m.setAccessible(true); - utfMethod = m; - } - catch (final NoSuchMethodException | SecurityException exc) { - throw new IllegalStateException( - "No usable DataOutputStream.writeUTF(String, DataOutput)", exc); + if (utflen > 65535) throw new UTFDataFormatException( + "encoded string too long: " + utflen + " bytes"); + final byte[] bytes = new byte[utflen + 2]; + bytes[0] = (byte) ((utflen >>> 8) & 0xFF); + bytes[1] = (byte) (utflen & 0xFF); + int pos = 2; + for (int i = 0; i < strlen; i++) { + final char c = str.charAt(i); + if (c >= '\u0001' && c <= '\u007F') { + bytes[pos++] = (byte) c; + } + else if (c <= '\u07FF') { + bytes[pos++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); + bytes[pos++] = (byte) (0x80 | (c & 0x3F)); + } + else { + bytes[pos++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); + bytes[pos++] = (byte) (0x80 | ((c >> 6) & 0x3F)); + bytes[pos++] = (byte) (0x80 | (c & 0x3F)); + } } + out.write(bytes); + return utflen + 2; } protected static IOException readOnlyException() { diff --git a/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java b/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java index 1349653a6..1cdbcdf46 100644 --- a/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java +++ b/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/DummyHandle.java b/src/main/java/org/scijava/io/handle/DummyHandle.java index a5b2754b9..74b2d24ab 100644 --- a/src/main/java/org/scijava/io/handle/DummyHandle.java +++ b/src/main/java/org/scijava/io/handle/DummyHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -48,6 +48,14 @@ public class DummyHandle extends AbstractDataHandle { private long offset; private long length; + // -- Constructors -- + + public DummyHandle() { } + + public DummyHandle(final DummyLocation location) { + set(location); + } + // -- DataHandle methods -- @Override diff --git a/src/main/java/org/scijava/io/handle/FileHandle.java b/src/main/java/org/scijava/io/handle/FileHandle.java index ad9822101..3734f7ebb 100644 --- a/src/main/java/org/scijava/io/handle/FileHandle.java +++ b/src/main/java/org/scijava/io/handle/FileHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -58,6 +58,14 @@ public class FileHandle extends AbstractDataHandle { /** True iff the {@link #close()} has already been called. */ private boolean closed; + // -- Constructors -- + + public FileHandle() { } + + public FileHandle(final FileLocation location) { + set(location); + } + // -- FileHandle methods -- /** diff --git a/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java b/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java index 1d26e20c0..fed7de110 100644 --- a/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java +++ b/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,7 +44,7 @@ * Read-only buffered {@link DataHandle}. It buffers the underlying handle into * a fixed number of pages, swapping them out when necessary. */ -public class ReadBufferDataHandle extends AbstractHigherOrderHandle { +public class ReadBufferDataHandle extends AbstractHigherOrderHandle { private static final int DEFAULT_PAGE_SIZE = 10_000; private static final int DEFAULT_NUM_PAGES = 10; @@ -55,6 +55,12 @@ public class ReadBufferDataHandle extends AbstractHigherOrderHandle { private final LRUReplacementStrategy replacementStrategy; private final Map pageToSlot; + /** + * Cached length value, for performance. When reading data, length is not + * expected to change, but querying it (e.g. via native filesystem access) + * can be slow, and we need to query the length frequently. + */ + private long length = -1; private long offset = 0l; private byte[] currentPage; private int currentPageID = -1; @@ -67,7 +73,7 @@ public class ReadBufferDataHandle extends AbstractHigherOrderHandle { * @param handle * the handle to wrap */ - public ReadBufferDataHandle(final DataHandle handle) { + public ReadBufferDataHandle(final DataHandle handle) { this(handle, DEFAULT_PAGE_SIZE); } @@ -80,7 +86,7 @@ public ReadBufferDataHandle(final DataHandle handle) { * @param pageSize * the size of the used pages */ - public ReadBufferDataHandle(final DataHandle handle, final int pageSize) { + public ReadBufferDataHandle(final DataHandle handle, final int pageSize) { this(handle, pageSize, DEFAULT_NUM_PAGES); } @@ -94,7 +100,7 @@ public ReadBufferDataHandle(final DataHandle handle, final int pageSiz * @param numPages * the number of pages to use */ - public ReadBufferDataHandle(final DataHandle handle, final int pageSize, final int numPages) { + public ReadBufferDataHandle(final DataHandle handle, final int pageSize, final int numPages) { super(handle); this.pageSize = pageSize; @@ -190,6 +196,12 @@ public void seek(final long pos) throws IOException { this.offset = pos; } + @Override + public long length() throws IOException { + if (length < 0) length = super.length(); + return length; + } + @Override public int read(final byte[] b, final int targetOffset, final int len) throws IOException diff --git a/src/main/java/org/scijava/io/handle/ResettableStreamHandle.java b/src/main/java/org/scijava/io/handle/ResettableStreamHandle.java index 17859653a..b4a7310f8 100644 --- a/src/main/java/org/scijava/io/handle/ResettableStreamHandle.java +++ b/src/main/java/org/scijava/io/handle/ResettableStreamHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/SeekableStreamHandle.java b/src/main/java/org/scijava/io/handle/SeekableStreamHandle.java index 1740b7b70..6b4746f56 100644 --- a/src/main/java/org/scijava/io/handle/SeekableStreamHandle.java +++ b/src/main/java/org/scijava/io/handle/SeekableStreamHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/StreamHandle.java b/src/main/java/org/scijava/io/handle/StreamHandle.java index 5a4169535..30a3e88ba 100644 --- a/src/main/java/org/scijava/io/handle/StreamHandle.java +++ b/src/main/java/org/scijava/io/handle/StreamHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java b/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java index db400b26a..f1549aa30 100644 --- a/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java +++ b/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/AbstractLocation.java b/src/main/java/org/scijava/io/location/AbstractLocation.java index a629c9b48..007a1a8a9 100644 --- a/src/main/java/org/scijava/io/location/AbstractLocation.java +++ b/src/main/java/org/scijava/io/location/AbstractLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/AbstractLocationResolver.java b/src/main/java/org/scijava/io/location/AbstractLocationResolver.java index 93616403e..b40f6c0d9 100644 --- a/src/main/java/org/scijava/io/location/AbstractLocationResolver.java +++ b/src/main/java/org/scijava/io/location/AbstractLocationResolver.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/AbstractRemoteLocation.java b/src/main/java/org/scijava/io/location/AbstractRemoteLocation.java index c36f21bbf..61b3f9735 100644 --- a/src/main/java/org/scijava/io/location/AbstractRemoteLocation.java +++ b/src/main/java/org/scijava/io/location/AbstractRemoteLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/BrowsableLocation.java b/src/main/java/org/scijava/io/location/BrowsableLocation.java index 312df412c..f6efc3b99 100644 --- a/src/main/java/org/scijava/io/location/BrowsableLocation.java +++ b/src/main/java/org/scijava/io/location/BrowsableLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/BytesLocation.java b/src/main/java/org/scijava/io/location/BytesLocation.java index 0d6210d69..0b7f604ed 100644 --- a/src/main/java/org/scijava/io/location/BytesLocation.java +++ b/src/main/java/org/scijava/io/location/BytesLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/DefaultLocationService.java b/src/main/java/org/scijava/io/location/DefaultLocationService.java index 92ba74047..028dd807e 100644 --- a/src/main/java/org/scijava/io/location/DefaultLocationService.java +++ b/src/main/java/org/scijava/io/location/DefaultLocationService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/DummyLocation.java b/src/main/java/org/scijava/io/location/DummyLocation.java index 676bd87df..0a9dd546f 100644 --- a/src/main/java/org/scijava/io/location/DummyLocation.java +++ b/src/main/java/org/scijava/io/location/DummyLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/FileLocation.java b/src/main/java/org/scijava/io/location/FileLocation.java index 03480c0ae..4cf688d3b 100644 --- a/src/main/java/org/scijava/io/location/FileLocation.java +++ b/src/main/java/org/scijava/io/location/FileLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/FileLocationResolver.java b/src/main/java/org/scijava/io/location/FileLocationResolver.java index b8d642d3e..5e6b19df0 100644 --- a/src/main/java/org/scijava/io/location/FileLocationResolver.java +++ b/src/main/java/org/scijava/io/location/FileLocationResolver.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/Location.java b/src/main/java/org/scijava/io/location/Location.java index 470c9cb22..2c579ad7e 100644 --- a/src/main/java/org/scijava/io/location/Location.java +++ b/src/main/java/org/scijava/io/location/Location.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/LocationResolver.java b/src/main/java/org/scijava/io/location/LocationResolver.java index 9dd2c650c..e4c60eada 100644 --- a/src/main/java/org/scijava/io/location/LocationResolver.java +++ b/src/main/java/org/scijava/io/location/LocationResolver.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/LocationService.java b/src/main/java/org/scijava/io/location/LocationService.java index 0d6104815..078eca44c 100644 --- a/src/main/java/org/scijava/io/location/LocationService.java +++ b/src/main/java/org/scijava/io/location/LocationService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -56,14 +56,15 @@ public interface LocationService extends HandlerService, */ default Location resolve(final String uriString) throws URISyntaxException { try { - return resolve(new URI(uriString)); + Location loc = resolve(new URI(uriString)); + if (loc != null) return loc; } catch (final URISyntaxException exc) { // In general, filenames are not valid URI strings. // Particularly on Windows, there are backslashes, which are invalid in URIs. // So we explicitly turn this string into a file if an error happens above. - return resolve(new File(uriString).toURI()); } + return resolve(new File(uriString).toURI()); } /** diff --git a/src/main/java/org/scijava/io/location/RemoteLocation.java b/src/main/java/org/scijava/io/location/RemoteLocation.java index f9bc1b608..20fd65fef 100644 --- a/src/main/java/org/scijava/io/location/RemoteLocation.java +++ b/src/main/java/org/scijava/io/location/RemoteLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/location/URILocation.java b/src/main/java/org/scijava/io/location/URILocation.java index 3311412e0..52621ea91 100644 --- a/src/main/java/org/scijava/io/location/URILocation.java +++ b/src/main/java/org/scijava/io/location/URILocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -112,7 +112,7 @@ private Map decodeQuery(final String query) { * @see URLDecoder */ private String decode(final String s) { - // http://stackoverflow.com/a/6926987 + // https://stackoverflow.com/a/6926987 try { return URLDecoder.decode(s.replace("+", "%2B"), "UTF-8"); } diff --git a/src/main/java/org/scijava/io/location/URLLocation.java b/src/main/java/org/scijava/io/location/URLLocation.java index d7e4ed49e..396dedeae 100644 --- a/src/main/java/org/scijava/io/location/URLLocation.java +++ b/src/main/java/org/scijava/io/location/URLLocation.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java b/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java index 8fb6b0c52..6f9ec504d 100644 --- a/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java +++ b/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/nio/DefaultNIOService.java b/src/main/java/org/scijava/io/nio/DefaultNIOService.java index 8bff57a73..2550caab8 100644 --- a/src/main/java/org/scijava/io/nio/DefaultNIOService.java +++ b/src/main/java/org/scijava/io/nio/DefaultNIOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/io/nio/NIOService.java b/src/main/java/org/scijava/io/nio/NIOService.java index cbc8d681d..5e90ced72 100644 --- a/src/main/java/org/scijava/io/nio/NIOService.java +++ b/src/main/java/org/scijava/io/nio/NIOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -60,8 +60,8 @@ public interface NIOService extends SciJavaService { * buffer. * @param newSize The buffer size. * @return A newly allocated or mapped NIO byte buffer. - * @see "http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5092131" - * @see "http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6417205" + * @see "https://bugs.java.com/bugdatabase/view_bug.do?bug_id=5092131" + * @see "https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6417205" * @throws IOException If there is an issue mapping, aligning or allocating * the buffer. */ diff --git a/src/main/java/org/scijava/log/AbstractLogService.java b/src/main/java/org/scijava/log/AbstractLogService.java index 5ae980645..099750f95 100644 --- a/src/main/java/org/scijava/log/AbstractLogService.java +++ b/src/main/java/org/scijava/log/AbstractLogService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/CallingClassUtils.java b/src/main/java/org/scijava/log/CallingClassUtils.java index fc1250e78..3a615a5b2 100644 --- a/src/main/java/org/scijava/log/CallingClassUtils.java +++ b/src/main/java/org/scijava/log/CallingClassUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/DefaultLogger.java b/src/main/java/org/scijava/log/DefaultLogger.java index f11ec5ae0..a5522aa50 100644 --- a/src/main/java/org/scijava/log/DefaultLogger.java +++ b/src/main/java/org/scijava/log/DefaultLogger.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java b/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java index d8d45c4d5..d562921e5 100644 --- a/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java +++ b/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/IgnoreAsCallingClass.java b/src/main/java/org/scijava/log/IgnoreAsCallingClass.java index 775c7b4ff..5aa4a690a 100644 --- a/src/main/java/org/scijava/log/IgnoreAsCallingClass.java +++ b/src/main/java/org/scijava/log/IgnoreAsCallingClass.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/LogLevel.java b/src/main/java/org/scijava/log/LogLevel.java index 276970ae2..aabab92aa 100644 --- a/src/main/java/org/scijava/log/LogLevel.java +++ b/src/main/java/org/scijava/log/LogLevel.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/LogListener.java b/src/main/java/org/scijava/log/LogListener.java index 8c4047849..19c03c71f 100644 --- a/src/main/java/org/scijava/log/LogListener.java +++ b/src/main/java/org/scijava/log/LogListener.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/LogMessage.java b/src/main/java/org/scijava/log/LogMessage.java index 235de87f1..dce591878 100644 --- a/src/main/java/org/scijava/log/LogMessage.java +++ b/src/main/java/org/scijava/log/LogMessage.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/LogService.java b/src/main/java/org/scijava/log/LogService.java index 4675e0eab..ad9cdb40b 100644 --- a/src/main/java/org/scijava/log/LogService.java +++ b/src/main/java/org/scijava/log/LogService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/LogSource.java b/src/main/java/org/scijava/log/LogSource.java index af8e6802e..5f03b1870 100644 --- a/src/main/java/org/scijava/log/LogSource.java +++ b/src/main/java/org/scijava/log/LogSource.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/Logged.java b/src/main/java/org/scijava/log/Logged.java index 8e15caf9e..bee37e0fa 100644 --- a/src/main/java/org/scijava/log/Logged.java +++ b/src/main/java/org/scijava/log/Logged.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/Logger.java b/src/main/java/org/scijava/log/Logger.java index eccb06796..c2657b0b0 100644 --- a/src/main/java/org/scijava/log/Logger.java +++ b/src/main/java/org/scijava/log/Logger.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/log/StderrLogService.java b/src/main/java/org/scijava/log/StderrLogService.java index f387991d2..8c67b082b 100644 --- a/src/main/java/org/scijava/log/StderrLogService.java +++ b/src/main/java/org/scijava/log/StderrLogService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/main/DefaultMainService.java b/src/main/java/org/scijava/main/DefaultMainService.java index 81677d5c2..699a78132 100644 --- a/src/main/java/org/scijava/main/DefaultMainService.java +++ b/src/main/java/org/scijava/main/DefaultMainService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/main/MainService.java b/src/main/java/org/scijava/main/MainService.java index f1e76b85f..36b92b89b 100644 --- a/src/main/java/org/scijava/main/MainService.java +++ b/src/main/java/org/scijava/main/MainService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/main/console/MainArgument.java b/src/main/java/org/scijava/main/console/MainArgument.java index 71a116fb6..0e0ebe29d 100644 --- a/src/main/java/org/scijava/main/console/MainArgument.java +++ b/src/main/java/org/scijava/main/console/MainArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/main/run/MainCodeRunner.java b/src/main/java/org/scijava/main/run/MainCodeRunner.java index f1da7f002..a18ae6b3b 100644 --- a/src/main/java/org/scijava/main/run/MainCodeRunner.java +++ b/src/main/java/org/scijava/main/run/MainCodeRunner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/AbstractMenuCreator.java b/src/main/java/org/scijava/menu/AbstractMenuCreator.java index 8d076304c..726639ae8 100644 --- a/src/main/java/org/scijava/menu/AbstractMenuCreator.java +++ b/src/main/java/org/scijava/menu/AbstractMenuCreator.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/DefaultMenuService.java b/src/main/java/org/scijava/menu/DefaultMenuService.java index 287e28e5b..74ed27285 100644 --- a/src/main/java/org/scijava/menu/DefaultMenuService.java +++ b/src/main/java/org/scijava/menu/DefaultMenuService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/MenuConstants.java b/src/main/java/org/scijava/menu/MenuConstants.java index 24e27506b..8c38942c9 100644 --- a/src/main/java/org/scijava/menu/MenuConstants.java +++ b/src/main/java/org/scijava/menu/MenuConstants.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/MenuCreator.java b/src/main/java/org/scijava/menu/MenuCreator.java index d5ddc13d9..386771672 100644 --- a/src/main/java/org/scijava/menu/MenuCreator.java +++ b/src/main/java/org/scijava/menu/MenuCreator.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/MenuService.java b/src/main/java/org/scijava/menu/MenuService.java index 1a9a98a13..ce9a5d36c 100644 --- a/src/main/java/org/scijava/menu/MenuService.java +++ b/src/main/java/org/scijava/menu/MenuService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/ShadowMenu.java b/src/main/java/org/scijava/menu/ShadowMenu.java index a364d827e..c5eaea4cd 100644 --- a/src/main/java/org/scijava/menu/ShadowMenu.java +++ b/src/main/java/org/scijava/menu/ShadowMenu.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -230,17 +230,24 @@ public URL getIconURL() { if (isLeaf()) iconPath = DEFAULT_ICON_PATH; else return null; } - final String className = moduleInfo.getDelegateClassName(); try { - final Class c = Types.load(className, false); + final Class c = moduleInfo.loadDelegateClass(); final URL iconURL = c.getResource(iconPath); if (iconURL == null) { if (log != null) log.error("Could not load icon: " + iconPath); } return iconURL; } + catch (final ClassNotFoundException exc) { + final String message = "Failed to load class: " + + moduleInfo.getDelegateClassName(); + if (log.isDebug()) log.debug(message, exc); + else log.error(message); + return null; + } catch (final IllegalArgumentException exc) { - final String message = "Could not load icon for class: " + className; + final String message = "Could not load icon for class: " + + moduleInfo.getDelegateClassName(); if (log.isDebug()) log.debug(message, exc); else log.error(message); return null; diff --git a/src/main/java/org/scijava/menu/ShadowMenuIterator.java b/src/main/java/org/scijava/menu/ShadowMenuIterator.java index 5c1471f7d..ea69e7a2f 100644 --- a/src/main/java/org/scijava/menu/ShadowMenuIterator.java +++ b/src/main/java/org/scijava/menu/ShadowMenuIterator.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/event/MenuEvent.java b/src/main/java/org/scijava/menu/event/MenuEvent.java index 56a29995a..ae0deaa13 100644 --- a/src/main/java/org/scijava/menu/event/MenuEvent.java +++ b/src/main/java/org/scijava/menu/event/MenuEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/event/MenusAddedEvent.java b/src/main/java/org/scijava/menu/event/MenusAddedEvent.java index 77b4626d4..a3fd70e2f 100644 --- a/src/main/java/org/scijava/menu/event/MenusAddedEvent.java +++ b/src/main/java/org/scijava/menu/event/MenusAddedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/event/MenusRemovedEvent.java b/src/main/java/org/scijava/menu/event/MenusRemovedEvent.java index 717f4be7c..24e3a8f93 100644 --- a/src/main/java/org/scijava/menu/event/MenusRemovedEvent.java +++ b/src/main/java/org/scijava/menu/event/MenusRemovedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/menu/event/MenusUpdatedEvent.java b/src/main/java/org/scijava/menu/event/MenusUpdatedEvent.java index 781a6c998..951daace8 100644 --- a/src/main/java/org/scijava/menu/event/MenusUpdatedEvent.java +++ b/src/main/java/org/scijava/menu/event/MenusUpdatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/AbstractModule.java b/src/main/java/org/scijava/module/AbstractModule.java index e30a52a1c..4ca6a4528 100644 --- a/src/main/java/org/scijava/module/AbstractModule.java +++ b/src/main/java/org/scijava/module/AbstractModule.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -160,8 +160,13 @@ public void resolveInput(final String name) { item.validate(this); } catch (final MethodCallException exc) { - // NB: Hacky, but avoids changing the API signature. - throw new RuntimeException(exc); + // NB: resolveInput cannot declare checked exceptions, so we wrap. + // Prefer the cause's message (the user-facing validation error) when + // available; otherwise fall back to the MethodCallException's message. + final Throwable cause = exc.getCause(); + final String message = (cause != null && cause.getMessage() != null && + !cause.getMessage().isEmpty()) ? cause.getMessage() : exc.getMessage(); + throw new RuntimeException(message, exc); } } resolvedInputs.add(name); diff --git a/src/main/java/org/scijava/module/AbstractModuleInfo.java b/src/main/java/org/scijava/module/AbstractModuleInfo.java index 196b11ab5..704ac4cd3 100644 --- a/src/main/java/org/scijava/module/AbstractModuleInfo.java +++ b/src/main/java/org/scijava/module/AbstractModuleInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/AbstractModuleItem.java b/src/main/java/org/scijava/module/AbstractModuleItem.java index b96941e8d..e2648cd2f 100644 --- a/src/main/java/org/scijava/module/AbstractModuleItem.java +++ b/src/main/java/org/scijava/module/AbstractModuleItem.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -210,7 +210,12 @@ public void validate(final Module module) throws MethodCallException { if (validaterRef == null) { validaterRef = new MethodRef(delegateObject.getClass(), getValidater()); } - validaterRef.execute(module.getDelegateObject()); + final Object result = validaterRef.executeWithResult(module.getDelegateObject()); + // If the validater returns a non-empty String, treat it as an error message. + if (result instanceof String) { + final String message = (String) result; + if (!message.isEmpty()) throw new MethodCallException(message); + } } @Override diff --git a/src/main/java/org/scijava/module/DefaultModuleService.java b/src/main/java/org/scijava/module/DefaultModuleService.java index 228cee0b1..c6dee7f42 100644 --- a/src/main/java/org/scijava/module/DefaultModuleService.java +++ b/src/main/java/org/scijava/module/DefaultModuleService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -74,7 +74,7 @@ public class DefaultModuleService extends AbstractService implements ModuleService { - @Parameter + @Parameter(required = false) private LogService log; @Parameter @@ -170,7 +170,7 @@ public Module createModule(final ModuleInfo info) { return module; } catch (final ModuleException exc) { - log.error("Cannot create module: " + info.getDelegateClassName(), exc); + if (log != null) log.error("Cannot create module: " + info.getDelegateClassName(), exc); } return null; } @@ -251,10 +251,10 @@ public M waitFor(final Future future) { return future.get(); } catch (final InterruptedException e) { - log.error("Module execution interrupted", e); + if (log != null) log.error("Module execution interrupted", e); } catch (final ExecutionException e) { - log.error("Error during module execution", e); + if (log != null) log.error("Error during module execution", e); } return null; } @@ -392,8 +392,10 @@ private Module getRegisteredModuleInstance(final ModuleInfo info) { } if (objects.size() > 1) { // there are multiple instances; it's not clear which one to use - log.warn("Ignoring multiple candidate module instances for class: " + - type.getName()); + if (log != null) { + log.warn("Ignoring multiple candidate module instances for class: " + + type.getName()); + } return null; } // found exactly one instance; return it! @@ -416,7 +418,7 @@ private Map createMap(final Object[] values) { final Map valueMap = (Map) values[0]; for (final Object key : valueMap.keySet()) { if (!(key instanceof String)) { - log.error("Invalid input name: " + key); + if (log != null) log.error("Invalid input name: " + key); continue; } final String name = (String) key; @@ -427,7 +429,7 @@ private Map createMap(final Object[] values) { } if (values.length % 2 != 0) { - log.error("Ignoring extraneous argument: " + values[values.length - 1]); + if (log != null) log.error("Ignoring extraneous argument: " + values[values.length - 1]); } // loop over list of key/value pairs @@ -436,7 +438,7 @@ private Map createMap(final Object[] values) { final Object key = values[2 * i]; final Object value = values[2 * i + 1]; if (!(key instanceof String)) { - log.error("Invalid input name: " + key); + if (log != null) log.error("Invalid input name: " + key); continue; } final String name = (String) key; @@ -459,7 +461,7 @@ private void assignInputs(final Module module, if (input == null) { // inputs whose name starts with a dot are implicitly known by convention if (!name.startsWith(".")) { - log.warn("Unmatched input: " + name); + if (log != null) log.warn("Unmatched input: " + name); } converted = value; } @@ -467,8 +469,10 @@ private void assignInputs(final Module module, final Class type = input.getType(); converted = convertService.convert(value, type); if (value != null && converted == null) { - log.error("For input " + name + ": incompatible object " + - value.getClass().getName() + " for type " + type.getName()); + if (log != null) { + log.error("For input " + name + ": incompatible object " + + value.getClass().getName() + " for type " + type.getName()); + } continue; } } diff --git a/src/main/java/org/scijava/module/DefaultMutableModule.java b/src/main/java/org/scijava/module/DefaultMutableModule.java index 29c28bdfb..0e646a212 100644 --- a/src/main/java/org/scijava/module/DefaultMutableModule.java +++ b/src/main/java/org/scijava/module/DefaultMutableModule.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/DefaultMutableModuleInfo.java b/src/main/java/org/scijava/module/DefaultMutableModuleInfo.java index a7b2c8de2..372776ab9 100644 --- a/src/main/java/org/scijava/module/DefaultMutableModuleInfo.java +++ b/src/main/java/org/scijava/module/DefaultMutableModuleInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/DefaultMutableModuleItem.java b/src/main/java/org/scijava/module/DefaultMutableModuleItem.java index fc74b85d0..c16ea80ec 100644 --- a/src/main/java/org/scijava/module/DefaultMutableModuleItem.java +++ b/src/main/java/org/scijava/module/DefaultMutableModuleItem.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/MethodCallException.java b/src/main/java/org/scijava/module/MethodCallException.java index 823220f4c..fc37d1313 100644 --- a/src/main/java/org/scijava/module/MethodCallException.java +++ b/src/main/java/org/scijava/module/MethodCallException.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/MethodRef.java b/src/main/java/org/scijava/module/MethodRef.java index 2761aaa25..f77883204 100644 --- a/src/main/java/org/scijava/module/MethodRef.java +++ b/src/main/java/org/scijava/module/MethodRef.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -62,9 +62,15 @@ public MethodRef(final Class clazz, final String methodName, public void execute(final Object obj, final Object... args) throws MethodCallException { - if (method == null) return; + executeWithResult(obj, args); + } + + public Object executeWithResult(final Object obj, final Object... args) + throws MethodCallException + { + if (method == null) return null; try { - method.invoke(obj, args); + return method.invoke(obj, args); } catch (final Exception exc) { // NB: Several types of exceptions; simpler to handle them all the same. diff --git a/src/main/java/org/scijava/module/Module.java b/src/main/java/org/scijava/module/Module.java index 35ae5decd..21e6730bf 100644 --- a/src/main/java/org/scijava/module/Module.java +++ b/src/main/java/org/scijava/module/Module.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/ModuleCanceledException.java b/src/main/java/org/scijava/module/ModuleCanceledException.java index df33ba8c9..f500a4167 100644 --- a/src/main/java/org/scijava/module/ModuleCanceledException.java +++ b/src/main/java/org/scijava/module/ModuleCanceledException.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/ModuleException.java b/src/main/java/org/scijava/module/ModuleException.java index 59d490f17..9f9f3cb7c 100644 --- a/src/main/java/org/scijava/module/ModuleException.java +++ b/src/main/java/org/scijava/module/ModuleException.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/ModuleIndex.java b/src/main/java/org/scijava/module/ModuleIndex.java index f40875599..998568f10 100644 --- a/src/main/java/org/scijava/module/ModuleIndex.java +++ b/src/main/java/org/scijava/module/ModuleIndex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/ModuleInfo.java b/src/main/java/org/scijava/module/ModuleInfo.java index bcf7107f5..c9b687177 100644 --- a/src/main/java/org/scijava/module/ModuleInfo.java +++ b/src/main/java/org/scijava/module/ModuleInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/ModuleItem.java b/src/main/java/org/scijava/module/ModuleItem.java index b226bcde0..95ea748b4 100644 --- a/src/main/java/org/scijava/module/ModuleItem.java +++ b/src/main/java/org/scijava/module/ModuleItem.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -126,11 +126,52 @@ public interface ModuleItem extends BasicDetails { /** * Invokes this item's validation function, if any, on the given module. - * + *

+ * The validation function may signal failure either by throwing an exception + * or by returning a non-empty {@link String} error message. + *

+ * + * @throws MethodCallException if validation fails or the method cannot be + * invoked. When the validater returns a non-empty String, a + * {@link MethodCallException} is thrown with that string as its + * message. * @see #getValidater() + * @see #validateMessage(Module) */ void validate(Module module) throws MethodCallException; + /** + * Validates this item's value in the given module, returning any error + * message rather than throwing. + *

+ * The validation function may signal failure either by throwing an exception + * or by returning a non-empty {@link String} error message. This method + * catches both cases and returns the error message as a string, or + * {@code null} if the value is valid. + *

+ * + * @return an error message if the value is invalid, or {@code null} if valid. + * @see #getValidater() + * @see #validate(Module) + */ + default String validateMessage(final Module module) { + try { + validate(module); + return null; + } + catch (final MethodCallException exc) { + // Unwrap to find the most informative message. + final Throwable cause = exc.getCause(); + if (cause != null && cause.getMessage() != null && + !cause.getMessage().isEmpty()) + { + return cause.getMessage(); + } + final String msg = exc.getMessage(); + return msg != null && !msg.isEmpty() ? msg : exc.toString(); + } + } + /** * Gets the function that is called whenever this item changes. *

diff --git a/src/main/java/org/scijava/module/ModuleRunner.java b/src/main/java/org/scijava/module/ModuleRunner.java index 0a4cff44e..ece995d8a 100644 --- a/src/main/java/org/scijava/module/ModuleRunner.java +++ b/src/main/java/org/scijava/module/ModuleRunner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,6 +39,7 @@ import org.scijava.event.EventService; import org.scijava.log.LogService; import org.scijava.module.event.ModuleCanceledEvent; +import org.scijava.module.event.ModuleErroredEvent; import org.scijava.module.event.ModuleExecutedEvent; import org.scijava.module.event.ModuleExecutingEvent; import org.scijava.module.event.ModuleFinishedEvent; @@ -144,36 +145,42 @@ public void run() { final String title = module.getInfo().getTitle(); - // announce start of execution process - if (ss != null) ss.showStatus("Running command: " + title); - if (es != null) es.publish(new ModuleStartedEvent(module)); - - // execute preprocessors - final ModulePreprocessor canceler = preProcess(); - if (canceler != null) { - // module execution was canceled by preprocessor - final String reason = canceler.getCancelReason(); - cancel(reason); - cleanupAndBroadcastCancelation(title, reason); - return; + try { + // announce start of execution process + if (ss != null) ss.showStatus("Running command: " + title); + if (es != null) es.publish(new ModuleStartedEvent(module)); + + // execute preprocessors + final ModulePreprocessor canceler = preProcess(); + if (canceler != null) { + // module execution was canceled by preprocessor + final String reason = canceler.getCancelReason(); + cancel(reason); + cleanupAndBroadcastCancelation(title, reason); + return; + } + + // execute module + if (es != null) es.publish(new ModuleExecutingEvent(module)); + module.run(); + if (isCanceled()) { + // module execution was canceled by the module itself + cleanupAndBroadcastCancelation(title, getCancelReason()); + return; + } + if (es != null) es.publish(new ModuleExecutedEvent(module)); + + // execute postprocessors + postProcess(); + + // announce completion of execution process + if (es != null) es.publish(new ModuleFinishedEvent(module)); + if (ss != null) ss.showStatus("Command finished: " + title); } - - // execute module - if (es != null) es.publish(new ModuleExecutingEvent(module)); - module.run(); - if (isCanceled()) { - // module execution was canceled by the module itself - cleanupAndBroadcastCancelation(title, getCancelReason()); - return; + catch (final Throwable t) { + cleanupAndBroadcastException(title, t); + throw t; } - if (es != null) es.publish(new ModuleExecutedEvent(module)); - - // execute postprocessors - postProcess(); - - // announce completion of execution process - if (es != null) es.publish(new ModuleFinishedEvent(module)); - if (ss != null) ss.showStatus("Command finished: " + title); } // -- Helper methods -- @@ -190,6 +197,17 @@ private void cleanupAndBroadcastCancelation(final String title, } } + private void cleanupAndBroadcastException(final String title, + final Throwable t) + { + final ModuleErroredEvent evt = new ModuleErroredEvent(module, t); + if (es != null) es.publish(evt); + if (log != null && !evt.isConsumed()) { + // Nothing else handled the error, so log it. + log.error("Command errored: " + title, t); + } + } + private boolean isCanceled() { return module instanceof Cancelable && ((Cancelable) module).isCanceled(); } diff --git a/src/main/java/org/scijava/module/ModuleService.java b/src/main/java/org/scijava/module/ModuleService.java index ffcbb4d0d..3f97a56e4 100644 --- a/src/main/java/org/scijava/module/ModuleService.java +++ b/src/main/java/org/scijava/module/ModuleService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/MutableModule.java b/src/main/java/org/scijava/module/MutableModule.java index 294a7c66a..3a907c854 100644 --- a/src/main/java/org/scijava/module/MutableModule.java +++ b/src/main/java/org/scijava/module/MutableModule.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/MutableModuleInfo.java b/src/main/java/org/scijava/module/MutableModuleInfo.java index 976603838..31aeb7280 100644 --- a/src/main/java/org/scijava/module/MutableModuleInfo.java +++ b/src/main/java/org/scijava/module/MutableModuleInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/MutableModuleItem.java b/src/main/java/org/scijava/module/MutableModuleItem.java index fc3dfa6a0..413950216 100644 --- a/src/main/java/org/scijava/module/MutableModuleItem.java +++ b/src/main/java/org/scijava/module/MutableModuleItem.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java b/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java index eef9c42d1..baa6ce737 100644 --- a/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleErroredEvent.java b/src/main/java/org/scijava/module/event/ModuleErroredEvent.java new file mode 100644 index 000000000..381cc0a4e --- /dev/null +++ b/src/main/java/org/scijava/module/event/ModuleErroredEvent.java @@ -0,0 +1,52 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.module.event; + +import org.scijava.module.Module; + +/** + * An event indicating a module execution has thrown an exception. + * + * @author Gabriel Selzer + */ +public class ModuleErroredEvent extends ModuleExecutionEvent { + + private final Throwable exc; + + public ModuleErroredEvent(final Module module, final Throwable exc) { + super(module); + this.exc = exc; + } + + public Throwable getException() { + return exc; + } + +} diff --git a/src/main/java/org/scijava/module/event/ModuleEvent.java b/src/main/java/org/scijava/module/event/ModuleEvent.java index f059dd3a9..9d402399a 100644 --- a/src/main/java/org/scijava/module/event/ModuleEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleExecutedEvent.java b/src/main/java/org/scijava/module/event/ModuleExecutedEvent.java index f8b17ed12..c8ec50ca5 100644 --- a/src/main/java/org/scijava/module/event/ModuleExecutedEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleExecutedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleExecutingEvent.java b/src/main/java/org/scijava/module/event/ModuleExecutingEvent.java index e3ba97c10..5110625e8 100644 --- a/src/main/java/org/scijava/module/event/ModuleExecutingEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleExecutingEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleExecutionEvent.java b/src/main/java/org/scijava/module/event/ModuleExecutionEvent.java index 3f6aa0c97..73bfa9d14 100644 --- a/src/main/java/org/scijava/module/event/ModuleExecutionEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleExecutionEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleFinishedEvent.java b/src/main/java/org/scijava/module/event/ModuleFinishedEvent.java index d72d0cd07..4c0f71dbf 100644 --- a/src/main/java/org/scijava/module/event/ModuleFinishedEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleFinishedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModulePostprocessEvent.java b/src/main/java/org/scijava/module/event/ModulePostprocessEvent.java index 6402c8e1a..e59f94ff2 100644 --- a/src/main/java/org/scijava/module/event/ModulePostprocessEvent.java +++ b/src/main/java/org/scijava/module/event/ModulePostprocessEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModulePreprocessEvent.java b/src/main/java/org/scijava/module/event/ModulePreprocessEvent.java index 0eedb7c05..7efdc11c7 100644 --- a/src/main/java/org/scijava/module/event/ModulePreprocessEvent.java +++ b/src/main/java/org/scijava/module/event/ModulePreprocessEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleProcessEvent.java b/src/main/java/org/scijava/module/event/ModuleProcessEvent.java index 8dba30973..f5ac20fe8 100644 --- a/src/main/java/org/scijava/module/event/ModuleProcessEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleProcessEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModuleStartedEvent.java b/src/main/java/org/scijava/module/event/ModuleStartedEvent.java index cbe7f0518..2b8f59393 100644 --- a/src/main/java/org/scijava/module/event/ModuleStartedEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleStartedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModulesAddedEvent.java b/src/main/java/org/scijava/module/event/ModulesAddedEvent.java index 8ef3dcf44..30107c4e7 100644 --- a/src/main/java/org/scijava/module/event/ModulesAddedEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesAddedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModulesListEvent.java b/src/main/java/org/scijava/module/event/ModulesListEvent.java index 7fba52f93..051edef8d 100644 --- a/src/main/java/org/scijava/module/event/ModulesListEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesListEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModulesRemovedEvent.java b/src/main/java/org/scijava/module/event/ModulesRemovedEvent.java index 87b43a956..495f9e7e2 100644 --- a/src/main/java/org/scijava/module/event/ModulesRemovedEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesRemovedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/event/ModulesUpdatedEvent.java b/src/main/java/org/scijava/module/event/ModulesUpdatedEvent.java index 610ad5a94..df5a9065d 100644 --- a/src/main/java/org/scijava/module/event/ModulesUpdatedEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesUpdatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/AbstractPostprocessorPlugin.java b/src/main/java/org/scijava/module/process/AbstractPostprocessorPlugin.java index 8242389bb..6e786753b 100644 --- a/src/main/java/org/scijava/module/process/AbstractPostprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/AbstractPostprocessorPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/AbstractPreprocessorPlugin.java b/src/main/java/org/scijava/module/process/AbstractPreprocessorPlugin.java index 93d3726a2..b9cb5de9d 100644 --- a/src/main/java/org/scijava/module/process/AbstractPreprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/AbstractPreprocessorPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/AbstractSingleInputPreprocessor.java b/src/main/java/org/scijava/module/process/AbstractSingleInputPreprocessor.java index 1fcdc7403..63e07cd2b 100644 --- a/src/main/java/org/scijava/module/process/AbstractSingleInputPreprocessor.java +++ b/src/main/java/org/scijava/module/process/AbstractSingleInputPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/CheckInputsPreprocessor.java b/src/main/java/org/scijava/module/process/CheckInputsPreprocessor.java index d5323ad2f..8bbfac881 100644 --- a/src/main/java/org/scijava/module/process/CheckInputsPreprocessor.java +++ b/src/main/java/org/scijava/module/process/CheckInputsPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/DebugPostprocessor.java b/src/main/java/org/scijava/module/process/DebugPostprocessor.java index 1927c68aa..e614afada 100644 --- a/src/main/java/org/scijava/module/process/DebugPostprocessor.java +++ b/src/main/java/org/scijava/module/process/DebugPostprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/DebugPreprocessor.java b/src/main/java/org/scijava/module/process/DebugPreprocessor.java index 69e9a0099..15f6afe1f 100644 --- a/src/main/java/org/scijava/module/process/DebugPreprocessor.java +++ b/src/main/java/org/scijava/module/process/DebugPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/DefaultValuePreprocessor.java b/src/main/java/org/scijava/module/process/DefaultValuePreprocessor.java index 7239743f9..fed93f7e9 100644 --- a/src/main/java/org/scijava/module/process/DefaultValuePreprocessor.java +++ b/src/main/java/org/scijava/module/process/DefaultValuePreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/GatewayPreprocessor.java b/src/main/java/org/scijava/module/process/GatewayPreprocessor.java index 86ad0eb5e..b3889d479 100644 --- a/src/main/java/org/scijava/module/process/GatewayPreprocessor.java +++ b/src/main/java/org/scijava/module/process/GatewayPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/InitPreprocessor.java b/src/main/java/org/scijava/module/process/InitPreprocessor.java index 2ca0e647b..d135614d6 100644 --- a/src/main/java/org/scijava/module/process/InitPreprocessor.java +++ b/src/main/java/org/scijava/module/process/InitPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/LoadInputsPreprocessor.java b/src/main/java/org/scijava/module/process/LoadInputsPreprocessor.java index 62b6ad5bd..eb405b424 100644 --- a/src/main/java/org/scijava/module/process/LoadInputsPreprocessor.java +++ b/src/main/java/org/scijava/module/process/LoadInputsPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/LoggerPreprocessor.java b/src/main/java/org/scijava/module/process/LoggerPreprocessor.java index 6145337ac..b096c5593 100644 --- a/src/main/java/org/scijava/module/process/LoggerPreprocessor.java +++ b/src/main/java/org/scijava/module/process/LoggerPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,6 +29,7 @@ package org.scijava.module.process; +import org.scijava.Priority; import org.scijava.log.LogService; import org.scijava.log.Logger; import org.scijava.module.Module; @@ -44,7 +45,7 @@ * * @author Matthias Arzt */ -@Plugin(type = PreprocessorPlugin.class) +@Plugin(type = PreprocessorPlugin.class, priority = Priority.VERY_HIGH) public class LoggerPreprocessor extends AbstractPreprocessorPlugin { @Parameter(required = false) diff --git a/src/main/java/org/scijava/module/process/ModulePostprocessor.java b/src/main/java/org/scijava/module/process/ModulePostprocessor.java index a64b52723..50a82900e 100644 --- a/src/main/java/org/scijava/module/process/ModulePostprocessor.java +++ b/src/main/java/org/scijava/module/process/ModulePostprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/ModulePreprocessor.java b/src/main/java/org/scijava/module/process/ModulePreprocessor.java index 293610033..ee9d2af22 100644 --- a/src/main/java/org/scijava/module/process/ModulePreprocessor.java +++ b/src/main/java/org/scijava/module/process/ModulePreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/ModuleProcessor.java b/src/main/java/org/scijava/module/process/ModuleProcessor.java index c14c275b3..605194d03 100644 --- a/src/main/java/org/scijava/module/process/ModuleProcessor.java +++ b/src/main/java/org/scijava/module/process/ModuleProcessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/PostprocessorPlugin.java b/src/main/java/org/scijava/module/process/PostprocessorPlugin.java index 07081b6c9..a010e0a6f 100644 --- a/src/main/java/org/scijava/module/process/PostprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/PostprocessorPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/PreprocessorPlugin.java b/src/main/java/org/scijava/module/process/PreprocessorPlugin.java index 66b10b86a..57ccdc92f 100644 --- a/src/main/java/org/scijava/module/process/PreprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/PreprocessorPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/SaveInputsPreprocessor.java b/src/main/java/org/scijava/module/process/SaveInputsPreprocessor.java index 1998a76d1..8f4596f76 100644 --- a/src/main/java/org/scijava/module/process/SaveInputsPreprocessor.java +++ b/src/main/java/org/scijava/module/process/SaveInputsPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/ServicePreprocessor.java b/src/main/java/org/scijava/module/process/ServicePreprocessor.java index 048f0da82..15ac626c5 100644 --- a/src/main/java/org/scijava/module/process/ServicePreprocessor.java +++ b/src/main/java/org/scijava/module/process/ServicePreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/process/ValidityPreprocessor.java b/src/main/java/org/scijava/module/process/ValidityPreprocessor.java index ac86b2020..e1cbdb29e 100644 --- a/src/main/java/org/scijava/module/process/ValidityPreprocessor.java +++ b/src/main/java/org/scijava/module/process/ValidityPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/module/run/ModuleCodeRunner.java b/src/main/java/org/scijava/module/run/ModuleCodeRunner.java index 2ee78144c..0369dee67 100644 --- a/src/main/java/org/scijava/module/run/ModuleCodeRunner.java +++ b/src/main/java/org/scijava/module/run/ModuleCodeRunner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/DefaultObjectService.java b/src/main/java/org/scijava/object/DefaultObjectService.java index 0b112b662..885f2025c 100644 --- a/src/main/java/org/scijava/object/DefaultObjectService.java +++ b/src/main/java/org/scijava/object/DefaultObjectService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/LazyObjects.java b/src/main/java/org/scijava/object/LazyObjects.java index 3fc476f79..3676085bb 100644 --- a/src/main/java/org/scijava/object/LazyObjects.java +++ b/src/main/java/org/scijava/object/LazyObjects.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/NamedObjectIndex.java b/src/main/java/org/scijava/object/NamedObjectIndex.java index 9cd2aeae6..0d807d166 100644 --- a/src/main/java/org/scijava/object/NamedObjectIndex.java +++ b/src/main/java/org/scijava/object/NamedObjectIndex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/ObjectIndex.java b/src/main/java/org/scijava/object/ObjectIndex.java index e97521043..5eb81dde1 100644 --- a/src/main/java/org/scijava/object/ObjectIndex.java +++ b/src/main/java/org/scijava/object/ObjectIndex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/ObjectService.java b/src/main/java/org/scijava/object/ObjectService.java index 392e476d5..fac395e5d 100644 --- a/src/main/java/org/scijava/object/ObjectService.java +++ b/src/main/java/org/scijava/object/ObjectService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/SortedObjectIndex.java b/src/main/java/org/scijava/object/SortedObjectIndex.java index 77b231a0c..a9d2d1f21 100644 --- a/src/main/java/org/scijava/object/SortedObjectIndex.java +++ b/src/main/java/org/scijava/object/SortedObjectIndex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ListEvent.java b/src/main/java/org/scijava/object/event/ListEvent.java index ecf3103e9..e7e5214f7 100644 --- a/src/main/java/org/scijava/object/event/ListEvent.java +++ b/src/main/java/org/scijava/object/event/ListEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ObjectCreatedEvent.java b/src/main/java/org/scijava/object/event/ObjectCreatedEvent.java index 7f0615f4c..0cbd3dad0 100644 --- a/src/main/java/org/scijava/object/event/ObjectCreatedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectCreatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ObjectDeletedEvent.java b/src/main/java/org/scijava/object/event/ObjectDeletedEvent.java index 47fc3c88c..793a20c02 100644 --- a/src/main/java/org/scijava/object/event/ObjectDeletedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectDeletedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ObjectEvent.java b/src/main/java/org/scijava/object/event/ObjectEvent.java index 80816a27b..7b1370612 100644 --- a/src/main/java/org/scijava/object/event/ObjectEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ObjectModifiedEvent.java b/src/main/java/org/scijava/object/event/ObjectModifiedEvent.java index 966294653..6e51bb9d2 100644 --- a/src/main/java/org/scijava/object/event/ObjectModifiedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectModifiedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ObjectsAddedEvent.java b/src/main/java/org/scijava/object/event/ObjectsAddedEvent.java index 9da819a74..c4ce0e854 100644 --- a/src/main/java/org/scijava/object/event/ObjectsAddedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectsAddedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ObjectsListEvent.java b/src/main/java/org/scijava/object/event/ObjectsListEvent.java index f9880b3e6..9bab39b51 100644 --- a/src/main/java/org/scijava/object/event/ObjectsListEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectsListEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/object/event/ObjectsRemovedEvent.java b/src/main/java/org/scijava/object/event/ObjectsRemovedEvent.java index 4a0872e99..c042a73f8 100644 --- a/src/main/java/org/scijava/object/event/ObjectsRemovedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectsRemovedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/options/DefaultOptionsService.java b/src/main/java/org/scijava/options/DefaultOptionsService.java index 7e44fb84a..aa6792276 100644 --- a/src/main/java/org/scijava/options/DefaultOptionsService.java +++ b/src/main/java/org/scijava/options/DefaultOptionsService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/options/OptionsPlugin.java b/src/main/java/org/scijava/options/OptionsPlugin.java index bda0f4df2..24208055c 100644 --- a/src/main/java/org/scijava/options/OptionsPlugin.java +++ b/src/main/java/org/scijava/options/OptionsPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/options/OptionsService.java b/src/main/java/org/scijava/options/OptionsService.java index 72ead76f2..6e659e1c9 100644 --- a/src/main/java/org/scijava/options/OptionsService.java +++ b/src/main/java/org/scijava/options/OptionsService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/options/event/OptionsEvent.java b/src/main/java/org/scijava/options/event/OptionsEvent.java index 48c53fffc..9ecea6af8 100644 --- a/src/main/java/org/scijava/options/event/OptionsEvent.java +++ b/src/main/java/org/scijava/options/event/OptionsEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/parse/DefaultParseService.java b/src/main/java/org/scijava/parse/DefaultParseService.java index 53bdbe46a..0924ab884 100644 --- a/src/main/java/org/scijava/parse/DefaultParseService.java +++ b/src/main/java/org/scijava/parse/DefaultParseService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/parse/Item.java b/src/main/java/org/scijava/parse/Item.java index efb86a527..416538777 100644 --- a/src/main/java/org/scijava/parse/Item.java +++ b/src/main/java/org/scijava/parse/Item.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/parse/Items.java b/src/main/java/org/scijava/parse/Items.java index a54117481..0b3b6becb 100644 --- a/src/main/java/org/scijava/parse/Items.java +++ b/src/main/java/org/scijava/parse/Items.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/parse/ParseService.java b/src/main/java/org/scijava/parse/ParseService.java index de88860dd..fe7ff2946 100644 --- a/src/main/java/org/scijava/parse/ParseService.java +++ b/src/main/java/org/scijava/parse/ParseService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/AbstractPlatform.java b/src/main/java/org/scijava/platform/AbstractPlatform.java index 6c8cfa5bc..9005f3024 100644 --- a/src/main/java/org/scijava/platform/AbstractPlatform.java +++ b/src/main/java/org/scijava/platform/AbstractPlatform.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/AppEventService.java b/src/main/java/org/scijava/platform/AppEventService.java index 26d2b4555..6227d6563 100644 --- a/src/main/java/org/scijava/platform/AppEventService.java +++ b/src/main/java/org/scijava/platform/AppEventService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/DefaultAppEventService.java b/src/main/java/org/scijava/platform/DefaultAppEventService.java index 2101d8c04..07809297d 100644 --- a/src/main/java/org/scijava/platform/DefaultAppEventService.java +++ b/src/main/java/org/scijava/platform/DefaultAppEventService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/DefaultPlatform.java b/src/main/java/org/scijava/platform/DefaultPlatform.java index 6d61317fe..18473f650 100644 --- a/src/main/java/org/scijava/platform/DefaultPlatform.java +++ b/src/main/java/org/scijava/platform/DefaultPlatform.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,6 +33,8 @@ import java.net.URL; import org.scijava.Priority; +import org.scijava.log.LogService; +import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; /** @@ -44,6 +46,9 @@ @Plugin(type = Platform.class, name = "Default", priority = Priority.VERY_LOW) public class DefaultPlatform extends AbstractPlatform { + @Parameter(required = false) + private LogService log; + // -- PlatformHandler methods -- /** @@ -66,9 +71,14 @@ public void open(final URL url) throws IOException { try { final int exitCode = getPlatformService().exec(browser, url.toString()); if (exitCode == 0) return; + else if (log != null) { + log.debug("Command '" + browser + + "' failed with exit code " + exitCode); + } } catch (final IOException e) { // browser executable was invalid; try the next one + if (log != null) log.debug("Command '" + browser + "' failed", e); } } throw new IOException("Could not open " + url); diff --git a/src/main/java/org/scijava/platform/DefaultPlatformService.java b/src/main/java/org/scijava/platform/DefaultPlatformService.java index 2a1c671ae..bb8c962a6 100644 --- a/src/main/java/org/scijava/platform/DefaultPlatformService.java +++ b/src/main/java/org/scijava/platform/DefaultPlatformService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/Platform.java b/src/main/java/org/scijava/platform/Platform.java index 3a663bb85..31cc2e86a 100644 --- a/src/main/java/org/scijava/platform/Platform.java +++ b/src/main/java/org/scijava/platform/Platform.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/PlatformService.java b/src/main/java/org/scijava/platform/PlatformService.java index 2f771bd35..ff66f8939 100644 --- a/src/main/java/org/scijava/platform/PlatformService.java +++ b/src/main/java/org/scijava/platform/PlatformService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppAboutEvent.java b/src/main/java/org/scijava/platform/event/AppAboutEvent.java index 46eed9b31..cd39d4764 100644 --- a/src/main/java/org/scijava/platform/event/AppAboutEvent.java +++ b/src/main/java/org/scijava/platform/event/AppAboutEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppFocusEvent.java b/src/main/java/org/scijava/platform/event/AppFocusEvent.java index 36d5605a0..e18e88a14 100644 --- a/src/main/java/org/scijava/platform/event/AppFocusEvent.java +++ b/src/main/java/org/scijava/platform/event/AppFocusEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppMenusCreatedEvent.java b/src/main/java/org/scijava/platform/event/AppMenusCreatedEvent.java index 1e9dd3f9e..3f8b80e0f 100644 --- a/src/main/java/org/scijava/platform/event/AppMenusCreatedEvent.java +++ b/src/main/java/org/scijava/platform/event/AppMenusCreatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppOpenFilesEvent.java b/src/main/java/org/scijava/platform/event/AppOpenFilesEvent.java index 5b3bdcde1..cf42e0a73 100644 --- a/src/main/java/org/scijava/platform/event/AppOpenFilesEvent.java +++ b/src/main/java/org/scijava/platform/event/AppOpenFilesEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppPreferencesEvent.java b/src/main/java/org/scijava/platform/event/AppPreferencesEvent.java index 2b4883129..f6cf5ce81 100644 --- a/src/main/java/org/scijava/platform/event/AppPreferencesEvent.java +++ b/src/main/java/org/scijava/platform/event/AppPreferencesEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppPrintEvent.java b/src/main/java/org/scijava/platform/event/AppPrintEvent.java index 013a70e79..2cfd3a56e 100644 --- a/src/main/java/org/scijava/platform/event/AppPrintEvent.java +++ b/src/main/java/org/scijava/platform/event/AppPrintEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppQuitEvent.java b/src/main/java/org/scijava/platform/event/AppQuitEvent.java index de8d9be40..0b5f5f1ac 100644 --- a/src/main/java/org/scijava/platform/event/AppQuitEvent.java +++ b/src/main/java/org/scijava/platform/event/AppQuitEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppReOpenEvent.java b/src/main/java/org/scijava/platform/event/AppReOpenEvent.java index 907e83148..a9db284a5 100644 --- a/src/main/java/org/scijava/platform/event/AppReOpenEvent.java +++ b/src/main/java/org/scijava/platform/event/AppReOpenEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppScreenSleepEvent.java b/src/main/java/org/scijava/platform/event/AppScreenSleepEvent.java index fcedfd3a3..d499a62db 100644 --- a/src/main/java/org/scijava/platform/event/AppScreenSleepEvent.java +++ b/src/main/java/org/scijava/platform/event/AppScreenSleepEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppSleepEvent.java b/src/main/java/org/scijava/platform/event/AppSleepEvent.java index 776b80fba..5ba427317 100644 --- a/src/main/java/org/scijava/platform/event/AppSleepEvent.java +++ b/src/main/java/org/scijava/platform/event/AppSleepEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppSystemSleepEvent.java b/src/main/java/org/scijava/platform/event/AppSystemSleepEvent.java index f7c426e3a..9e86cadf2 100644 --- a/src/main/java/org/scijava/platform/event/AppSystemSleepEvent.java +++ b/src/main/java/org/scijava/platform/event/AppSystemSleepEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppUserSessionEvent.java b/src/main/java/org/scijava/platform/event/AppUserSessionEvent.java index e3ee34255..fb202cbc3 100644 --- a/src/main/java/org/scijava/platform/event/AppUserSessionEvent.java +++ b/src/main/java/org/scijava/platform/event/AppUserSessionEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/AppVisibleEvent.java b/src/main/java/org/scijava/platform/event/AppVisibleEvent.java index 307895791..1b6fd77d2 100644 --- a/src/main/java/org/scijava/platform/event/AppVisibleEvent.java +++ b/src/main/java/org/scijava/platform/event/AppVisibleEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/platform/event/ApplicationEvent.java b/src/main/java/org/scijava/platform/event/ApplicationEvent.java index 0b359cd46..da0a2f3a1 100644 --- a/src/main/java/org/scijava/platform/event/ApplicationEvent.java +++ b/src/main/java/org/scijava/platform/event/ApplicationEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractHandlerPlugin.java b/src/main/java/org/scijava/plugin/AbstractHandlerPlugin.java index 3187fcd23..2077a94c0 100644 --- a/src/main/java/org/scijava/plugin/AbstractHandlerPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractHandlerPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractHandlerService.java b/src/main/java/org/scijava/plugin/AbstractHandlerService.java index 4ede3e5aa..65873e6eb 100644 --- a/src/main/java/org/scijava/plugin/AbstractHandlerService.java +++ b/src/main/java/org/scijava/plugin/AbstractHandlerService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractPTService.java b/src/main/java/org/scijava/plugin/AbstractPTService.java index 7d96d2770..5273d007b 100644 --- a/src/main/java/org/scijava/plugin/AbstractPTService.java +++ b/src/main/java/org/scijava/plugin/AbstractPTService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractRichPlugin.java b/src/main/java/org/scijava/plugin/AbstractRichPlugin.java index 2d53decac..205d8ce8c 100644 --- a/src/main/java/org/scijava/plugin/AbstractRichPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractRichPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractSingletonService.java b/src/main/java/org/scijava/plugin/AbstractSingletonService.java index c54f26ee5..b7f65c684 100644 --- a/src/main/java/org/scijava/plugin/AbstractSingletonService.java +++ b/src/main/java/org/scijava/plugin/AbstractSingletonService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java b/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java index 8d9e4a1f3..a9a12fb89 100644 --- a/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractTypedService.java b/src/main/java/org/scijava/plugin/AbstractTypedService.java index 17ea8f400..c747223f3 100644 --- a/src/main/java/org/scijava/plugin/AbstractTypedService.java +++ b/src/main/java/org/scijava/plugin/AbstractTypedService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractWrapperPlugin.java b/src/main/java/org/scijava/plugin/AbstractWrapperPlugin.java index 26fcc5e47..4a8d11412 100644 --- a/src/main/java/org/scijava/plugin/AbstractWrapperPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractWrapperPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/AbstractWrapperService.java b/src/main/java/org/scijava/plugin/AbstractWrapperService.java index 516ad9d69..9bd224855 100644 --- a/src/main/java/org/scijava/plugin/AbstractWrapperService.java +++ b/src/main/java/org/scijava/plugin/AbstractWrapperService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/Attr.java b/src/main/java/org/scijava/plugin/Attr.java index d45a4f0b0..1dce1f4d7 100644 --- a/src/main/java/org/scijava/plugin/Attr.java +++ b/src/main/java/org/scijava/plugin/Attr.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/DefaultPluginFinder.java b/src/main/java/org/scijava/plugin/DefaultPluginFinder.java index 99fc8fd18..bd3a0eb08 100644 --- a/src/main/java/org/scijava/plugin/DefaultPluginFinder.java +++ b/src/main/java/org/scijava/plugin/DefaultPluginFinder.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/DefaultPluginService.java b/src/main/java/org/scijava/plugin/DefaultPluginService.java index 02b905f56..096e75c92 100644 --- a/src/main/java/org/scijava/plugin/DefaultPluginService.java +++ b/src/main/java/org/scijava/plugin/DefaultPluginService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/HandlerPlugin.java b/src/main/java/org/scijava/plugin/HandlerPlugin.java index b511aab11..8abcba382 100644 --- a/src/main/java/org/scijava/plugin/HandlerPlugin.java +++ b/src/main/java/org/scijava/plugin/HandlerPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/HandlerService.java b/src/main/java/org/scijava/plugin/HandlerService.java index 1a2bfa119..dec2d71b5 100644 --- a/src/main/java/org/scijava/plugin/HandlerService.java +++ b/src/main/java/org/scijava/plugin/HandlerService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/HasPluginInfo.java b/src/main/java/org/scijava/plugin/HasPluginInfo.java index 19c3da732..622429d98 100644 --- a/src/main/java/org/scijava/plugin/HasPluginInfo.java +++ b/src/main/java/org/scijava/plugin/HasPluginInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/Menu.java b/src/main/java/org/scijava/plugin/Menu.java index 0c00e546b..ce861c6b6 100644 --- a/src/main/java/org/scijava/plugin/Menu.java +++ b/src/main/java/org/scijava/plugin/Menu.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/PTService.java b/src/main/java/org/scijava/plugin/PTService.java index 4feb02532..d0e61a997 100644 --- a/src/main/java/org/scijava/plugin/PTService.java +++ b/src/main/java/org/scijava/plugin/PTService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/Parameter.java b/src/main/java/org/scijava/plugin/Parameter.java index 0a41c094d..edc1da1af 100644 --- a/src/main/java/org/scijava/plugin/Parameter.java +++ b/src/main/java/org/scijava/plugin/Parameter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -71,7 +71,7 @@ * */ // NB: We use the fully qualified name to work around a javac bug: - // http://bugs.sun.com/view_bug.do?bug_id=6512707 + // https://bugs.java.com/view_bug.do?bug_id=6512707 // See: // http://groups.google.com/group/project-lombok/browse_thread/thread/c5568eb659cab203 ItemIO type() default org.scijava.ItemIO.INPUT; diff --git a/src/main/java/org/scijava/plugin/Plugin.java b/src/main/java/org/scijava/plugin/Plugin.java index a1f7af866..cd1701881 100644 --- a/src/main/java/org/scijava/plugin/Plugin.java +++ b/src/main/java/org/scijava/plugin/Plugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/PluginFinder.java b/src/main/java/org/scijava/plugin/PluginFinder.java index 0b9ff441e..9f193a90e 100644 --- a/src/main/java/org/scijava/plugin/PluginFinder.java +++ b/src/main/java/org/scijava/plugin/PluginFinder.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/PluginIndex.java b/src/main/java/org/scijava/plugin/PluginIndex.java index 73763ef03..ea3aa8fdc 100644 --- a/src/main/java/org/scijava/plugin/PluginIndex.java +++ b/src/main/java/org/scijava/plugin/PluginIndex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -88,7 +88,7 @@ public PluginIndex() { */ @SuppressWarnings({ "rawtypes", "unchecked" }) public PluginIndex(final PluginFinder pluginFinder) { - // NB: See: http://stackoverflow.com/questions/4765520/ + // NB: See: https://stackoverflow.com/questions/4765520/ super((Class) PluginInfo.class); this.pluginFinder = pluginFinder; } diff --git a/src/main/java/org/scijava/plugin/PluginInfo.java b/src/main/java/org/scijava/plugin/PluginInfo.java index a9e4b5e09..85bab5954 100644 --- a/src/main/java/org/scijava/plugin/PluginInfo.java +++ b/src/main/java/org/scijava/plugin/PluginInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/PluginService.java b/src/main/java/org/scijava/plugin/PluginService.java index 07f44a6ca..644268b87 100644 --- a/src/main/java/org/scijava/plugin/PluginService.java +++ b/src/main/java/org/scijava/plugin/PluginService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/RichPlugin.java b/src/main/java/org/scijava/plugin/RichPlugin.java index d649eb5aa..891cc7822 100644 --- a/src/main/java/org/scijava/plugin/RichPlugin.java +++ b/src/main/java/org/scijava/plugin/RichPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/SciJavaPlugin.java b/src/main/java/org/scijava/plugin/SciJavaPlugin.java index ff4bd3c7a..97675e8bc 100644 --- a/src/main/java/org/scijava/plugin/SciJavaPlugin.java +++ b/src/main/java/org/scijava/plugin/SciJavaPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/SingletonPlugin.java b/src/main/java/org/scijava/plugin/SingletonPlugin.java index b26ee37cc..72b5da303 100644 --- a/src/main/java/org/scijava/plugin/SingletonPlugin.java +++ b/src/main/java/org/scijava/plugin/SingletonPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/SingletonService.java b/src/main/java/org/scijava/plugin/SingletonService.java index 07c2ff091..a60622eac 100644 --- a/src/main/java/org/scijava/plugin/SingletonService.java +++ b/src/main/java/org/scijava/plugin/SingletonService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/SortablePlugin.java b/src/main/java/org/scijava/plugin/SortablePlugin.java index e3ab8e244..e7f005db9 100644 --- a/src/main/java/org/scijava/plugin/SortablePlugin.java +++ b/src/main/java/org/scijava/plugin/SortablePlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/TypedPlugin.java b/src/main/java/org/scijava/plugin/TypedPlugin.java index 26ae5468e..31153089a 100644 --- a/src/main/java/org/scijava/plugin/TypedPlugin.java +++ b/src/main/java/org/scijava/plugin/TypedPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/TypedService.java b/src/main/java/org/scijava/plugin/TypedService.java index 26f1c60bf..74701f46c 100644 --- a/src/main/java/org/scijava/plugin/TypedService.java +++ b/src/main/java/org/scijava/plugin/TypedService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/WrapperPlugin.java b/src/main/java/org/scijava/plugin/WrapperPlugin.java index d867aeef8..651bf634e 100644 --- a/src/main/java/org/scijava/plugin/WrapperPlugin.java +++ b/src/main/java/org/scijava/plugin/WrapperPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/WrapperService.java b/src/main/java/org/scijava/plugin/WrapperService.java index 2377a9fef..4274f16e8 100644 --- a/src/main/java/org/scijava/plugin/WrapperService.java +++ b/src/main/java/org/scijava/plugin/WrapperService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/event/PluginsAddedEvent.java b/src/main/java/org/scijava/plugin/event/PluginsAddedEvent.java index cae5e3792..edfc5b32e 100644 --- a/src/main/java/org/scijava/plugin/event/PluginsAddedEvent.java +++ b/src/main/java/org/scijava/plugin/event/PluginsAddedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/event/PluginsListEvent.java b/src/main/java/org/scijava/plugin/event/PluginsListEvent.java index 927d76bee..af6bf4dc3 100644 --- a/src/main/java/org/scijava/plugin/event/PluginsListEvent.java +++ b/src/main/java/org/scijava/plugin/event/PluginsListEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/plugin/event/PluginsRemovedEvent.java b/src/main/java/org/scijava/plugin/event/PluginsRemovedEvent.java index f46d54bf9..baf9961a3 100644 --- a/src/main/java/org/scijava/plugin/event/PluginsRemovedEvent.java +++ b/src/main/java/org/scijava/plugin/event/PluginsRemovedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/prefs/AbstractPrefService.java b/src/main/java/org/scijava/prefs/AbstractPrefService.java index 8fc849c20..052603404 100644 --- a/src/main/java/org/scijava/prefs/AbstractPrefService.java +++ b/src/main/java/org/scijava/prefs/AbstractPrefService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/prefs/DefaultPrefService.java b/src/main/java/org/scijava/prefs/DefaultPrefService.java index 76a688924..3c192f62b 100644 --- a/src/main/java/org/scijava/prefs/DefaultPrefService.java +++ b/src/main/java/org/scijava/prefs/DefaultPrefService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/prefs/PrefService.java b/src/main/java/org/scijava/prefs/PrefService.java index 9e787f436..98115b323 100644 --- a/src/main/java/org/scijava/prefs/PrefService.java +++ b/src/main/java/org/scijava/prefs/PrefService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/run/AbstractCodeRunner.java b/src/main/java/org/scijava/run/AbstractCodeRunner.java index 37ebab4cb..a10bd9205 100644 --- a/src/main/java/org/scijava/run/AbstractCodeRunner.java +++ b/src/main/java/org/scijava/run/AbstractCodeRunner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/run/CodeRunner.java b/src/main/java/org/scijava/run/CodeRunner.java index 13062df91..2efa316e2 100644 --- a/src/main/java/org/scijava/run/CodeRunner.java +++ b/src/main/java/org/scijava/run/CodeRunner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/run/DefaultRunService.java b/src/main/java/org/scijava/run/DefaultRunService.java index cb9a7249e..68239a4d7 100644 --- a/src/main/java/org/scijava/run/DefaultRunService.java +++ b/src/main/java/org/scijava/run/DefaultRunService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/run/RunService.java b/src/main/java/org/scijava/run/RunService.java index e0f8de3bb..738cfb078 100644 --- a/src/main/java/org/scijava/run/RunService.java +++ b/src/main/java/org/scijava/run/RunService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/run/console/RunArgument.java b/src/main/java/org/scijava/run/console/RunArgument.java index ba056a6e8..028440a5e 100644 --- a/src/main/java/org/scijava/run/console/RunArgument.java +++ b/src/main/java/org/scijava/run/console/RunArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AbstractAutoCompleter.java b/src/main/java/org/scijava/script/AbstractAutoCompleter.java index b8368dbff..ae255f5a2 100644 --- a/src/main/java/org/scijava/script/AbstractAutoCompleter.java +++ b/src/main/java/org/scijava/script/AbstractAutoCompleter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AbstractScriptContext.java b/src/main/java/org/scijava/script/AbstractScriptContext.java index abd258195..3f69d608a 100644 --- a/src/main/java/org/scijava/script/AbstractScriptContext.java +++ b/src/main/java/org/scijava/script/AbstractScriptContext.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AbstractScriptEngine.java b/src/main/java/org/scijava/script/AbstractScriptEngine.java index f306ee488..c64f967c3 100644 --- a/src/main/java/org/scijava/script/AbstractScriptEngine.java +++ b/src/main/java/org/scijava/script/AbstractScriptEngine.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AbstractScriptHeader.java b/src/main/java/org/scijava/script/AbstractScriptHeader.java index 41b3185bc..6dcf2650c 100644 --- a/src/main/java/org/scijava/script/AbstractScriptHeader.java +++ b/src/main/java/org/scijava/script/AbstractScriptHeader.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AbstractScriptLanguage.java b/src/main/java/org/scijava/script/AbstractScriptLanguage.java index 0f65a99c2..6f048fc89 100644 --- a/src/main/java/org/scijava/script/AbstractScriptLanguage.java +++ b/src/main/java/org/scijava/script/AbstractScriptLanguage.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AdaptedScriptEngine.java b/src/main/java/org/scijava/script/AdaptedScriptEngine.java index 39c8012a3..14e0d5a72 100644 --- a/src/main/java/org/scijava/script/AdaptedScriptEngine.java +++ b/src/main/java/org/scijava/script/AdaptedScriptEngine.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AdaptedScriptLanguage.java b/src/main/java/org/scijava/script/AdaptedScriptLanguage.java index ad952d54d..695c214a9 100644 --- a/src/main/java/org/scijava/script/AdaptedScriptLanguage.java +++ b/src/main/java/org/scijava/script/AdaptedScriptLanguage.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AutoCompleter.java b/src/main/java/org/scijava/script/AutoCompleter.java index f56ec50fb..334addd58 100644 --- a/src/main/java/org/scijava/script/AutoCompleter.java +++ b/src/main/java/org/scijava/script/AutoCompleter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/AutoCompletionResult.java b/src/main/java/org/scijava/script/AutoCompletionResult.java index 89ae99097..8f5ac4d5c 100644 --- a/src/main/java/org/scijava/script/AutoCompletionResult.java +++ b/src/main/java/org/scijava/script/AutoCompletionResult.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/CodeGenerator.java b/src/main/java/org/scijava/script/CodeGenerator.java index 7e95f1e78..894ce8f54 100644 --- a/src/main/java/org/scijava/script/CodeGenerator.java +++ b/src/main/java/org/scijava/script/CodeGenerator.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/CodeGeneratorJava.java b/src/main/java/org/scijava/script/CodeGeneratorJava.java index 7f75c39fd..84e9e09c1 100644 --- a/src/main/java/org/scijava/script/CodeGeneratorJava.java +++ b/src/main/java/org/scijava/script/CodeGeneratorJava.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/DefaultAutoCompleter.java b/src/main/java/org/scijava/script/DefaultAutoCompleter.java index 95bcc94c0..2de11644b 100644 --- a/src/main/java/org/scijava/script/DefaultAutoCompleter.java +++ b/src/main/java/org/scijava/script/DefaultAutoCompleter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/DefaultScriptHeaderService.java b/src/main/java/org/scijava/script/DefaultScriptHeaderService.java index 39941978e..284479134 100644 --- a/src/main/java/org/scijava/script/DefaultScriptHeaderService.java +++ b/src/main/java/org/scijava/script/DefaultScriptHeaderService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/DefaultScriptInterpreter.java b/src/main/java/org/scijava/script/DefaultScriptInterpreter.java index 147c141af..d3448d373 100644 --- a/src/main/java/org/scijava/script/DefaultScriptInterpreter.java +++ b/src/main/java/org/scijava/script/DefaultScriptInterpreter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -46,7 +46,7 @@ * The default implementation of a {@link ScriptInterpreter}. *

* Credit to Jason Sachs for the multi-line evaluation (see - * his post on StackOverflow). + * his post on StackOverflow). *

* * @author Johannes Schindelin @@ -174,7 +174,7 @@ public Object eval(final String command) throws ScriptException { * fact that there was a syntax error in the 2nd line. * *

- * For further details, see SO + * For further details, see SO * #5584674. *

*/ diff --git a/src/main/java/org/scijava/script/DefaultScriptService.java b/src/main/java/org/scijava/script/DefaultScriptService.java index 188123998..72b2403d3 100644 --- a/src/main/java/org/scijava/script/DefaultScriptService.java +++ b/src/main/java/org/scijava/script/DefaultScriptService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -385,7 +385,10 @@ private void addAliases(final HashMap> map, } private Class[] pluginClasses(final Class type) { - return pluginService.getPluginsOfType(type).stream().map(info -> { + return pluginService.getPluginsOfType(type).stream() // + .filter(info -> !info.is("noAlias")) // + .map(info -> + { try { return info.loadClass(); } diff --git a/src/main/java/org/scijava/script/InvocationObject.java b/src/main/java/org/scijava/script/InvocationObject.java index a7f373a7c..3d9c0ce55 100644 --- a/src/main/java/org/scijava/script/InvocationObject.java +++ b/src/main/java/org/scijava/script/InvocationObject.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/ParameterObject.java b/src/main/java/org/scijava/script/ParameterObject.java index 184fb8209..2f18323b8 100644 --- a/src/main/java/org/scijava/script/ParameterObject.java +++ b/src/main/java/org/scijava/script/ParameterObject.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/ScriptCLI.java b/src/main/java/org/scijava/script/ScriptCLI.java new file mode 100644 index 000000000..e20cf8918 --- /dev/null +++ b/src/main/java/org/scijava/script/ScriptCLI.java @@ -0,0 +1,169 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.script; + +import java.io.File; +import java.io.FileReader; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.scijava.Context; +import org.scijava.log.LogLevel; +import org.scijava.log.LogService; +import org.scijava.module.Module; + +/** + * A command-line entry point for running SciJava scripts. + * + * @author Curtis Rueden + */ +public class ScriptCLI { + + private static final String USAGE = "" + // + "Usage: " + ScriptCLI.class.getSimpleName() + // + " [-d] [-h] [-l language] [-o] [-r] /path/to/script [script-args]\n" + // + "\n" + // + "Options:\n" + // + " -d, --debug : enable debug-level log output\n" + // + " -h, --help : display this help message\n" + // + " -l, --language : specify language of script to execute\n" + // + " otherwise, inferred from script extension\n" + // + " -o, --print-outputs : print output values\n" + // + " -r, --print-return-value : print return value\n" + // + "\n" + // + "To read from stdin, use a dash (-) symbol for the script path.\n" + // + "\n" + // + "For script-args, give space-separated key=value pairs,\n" + // + "while will be passed in as SciJava script arguments."; + + public static void main(String... args) throws Exception { + final Map inputs = new HashMap<>(); + File file = null; + String language = null; + boolean printOutputs = false; + boolean printReturnValue = false; + boolean parsingOptions = true; + try (final Context context = new Context()) { + // Parse command-line arguments. + if (args.length == 0) args = new String[] {"-h"}; + for (int i = 0; i < args.length; i++) { + if (parsingOptions) { + // Parse options and filename. + if (args[i].equals("-d") || args[i].equals("--debug")) { + final LogService log = context.getService(LogService.class); + if (log != null) log.setLevel(LogLevel.DEBUG); + } + else if (args[i].equals("-h") || args[i].equals("--help")) { + System.err.println(USAGE); + System.exit(1); + } + else if (i < args.length - 1 && // + args[i].equals("-l") || args[i].equals("--language")) + { + language = args[++i]; + } + else if (args[i].equals("-o") || args[i].equals("--print-outputs")) { + printOutputs = true; + } + else if (args[i].equals("-r") || args[i].equals("--print-return-value")) { + printReturnValue = true; + } + else if (args[i].equals("-")) { + // read from stdin + parsingOptions = false; + } + else if (i < args.length - 1 && args[i].equals("--")) { + // argument after the -- separator must be the filename. + file = new File(args[++i]); + parsingOptions = false; + } + else if (new File(args[i]).exists()) { + file = new File(args[i]); + parsingOptions = false; + } + else { + System.err.println("Invalid argument: " + args[i]); + System.exit(2); + } + } + else { + // Parse script arguments. + final int equals = args[i].indexOf("="); + if (equals < 0) { + System.err.println("Invalid argument: " + args[i]); + System.exit(3); + } + final String key = args[i].substring(0, equals); + final String val = args[i].substring(equals + 1); + inputs.put(key, val); + } + } + + final ScriptService ss = context.getService(ScriptService.class); + if (ss == null) { + System.err.println("Error: No script service available."); + System.exit(4); + } + if (file == null && language == null) { + System.err.println("Error: Must specify language when using stdin."); + System.exit(5); + } + + final Module m; + if (language == null) { + m = ss.run(file, true, inputs).get(); + } + else { + ScriptLanguage lang = ss.getLanguageByName(language); + if (lang == null) lang = ss.getLanguageByExtension(language); + if (lang == null) { + System.err.println("Error: Unsupported language: " + language); + System.exit(6); + } + final Reader reader = file == null ? // + new InputStreamReader(System.in) : // + new FileReader(file); + m = ss.run("." + language, reader, true, inputs).get(); + } + if (printOutputs) { + for (Entry output : m.getOutputs().entrySet()) { + System.out.println(output.getKey() + " = " + output.getValue()); + } + } + if (printReturnValue && m instanceof ScriptModule) { + System.out.println(((ScriptModule) m).getReturnValue()); + } + } + System.exit(0); + } +} diff --git a/src/main/java/org/scijava/script/ScriptFinder.java b/src/main/java/org/scijava/script/ScriptFinder.java index 13f3fb37a..89e4c1b16 100644 --- a/src/main/java/org/scijava/script/ScriptFinder.java +++ b/src/main/java/org/scijava/script/ScriptFinder.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,6 +41,7 @@ import org.scijava.AbstractContextual; import org.scijava.Context; +import org.scijava.MenuEntry; import org.scijava.MenuPath; import org.scijava.log.LogService; import org.scijava.plugin.Parameter; @@ -178,8 +179,11 @@ private int createInfos(final List scripts, final Set urls, // friendlyPath = "File/Import/Movie File..." // menuPath = File > Import > Movie File... - // NB: Ignore base-level scripts (not nested in any menu). - if (menuPath.size() == 1) continue; + // Place base-level scripts in the "Plugins>Scripts" submenu + if (menuPath.size() == 1){ + menuPath.add(0, new MenuEntry("Plugins")); + menuPath.add(1, new MenuEntry("Scripts")); + } final URL url = scriptMap.get(path); diff --git a/src/main/java/org/scijava/script/ScriptHeader.java b/src/main/java/org/scijava/script/ScriptHeader.java index 57ca01749..417551358 100644 --- a/src/main/java/org/scijava/script/ScriptHeader.java +++ b/src/main/java/org/scijava/script/ScriptHeader.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/ScriptHeaderService.java b/src/main/java/org/scijava/script/ScriptHeaderService.java index 692869a8f..a58dd7f81 100644 --- a/src/main/java/org/scijava/script/ScriptHeaderService.java +++ b/src/main/java/org/scijava/script/ScriptHeaderService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/ScriptInfo.java b/src/main/java/org/scijava/script/ScriptInfo.java index 02b6c46cf..8b9f1734e 100644 --- a/src/main/java/org/scijava/script/ScriptInfo.java +++ b/src/main/java/org/scijava/script/ScriptInfo.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/ScriptInterpreter.java b/src/main/java/org/scijava/script/ScriptInterpreter.java index df59b6a36..b48ad3254 100644 --- a/src/main/java/org/scijava/script/ScriptInterpreter.java +++ b/src/main/java/org/scijava/script/ScriptInterpreter.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/ScriptLanguage.java b/src/main/java/org/scijava/script/ScriptLanguage.java index e8c1be0cc..af1c27fc5 100644 --- a/src/main/java/org/scijava/script/ScriptLanguage.java +++ b/src/main/java/org/scijava/script/ScriptLanguage.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/ScriptLanguageIndex.java b/src/main/java/org/scijava/script/ScriptLanguageIndex.java index 728c20831..b9e07d602 100644 --- a/src/main/java/org/scijava/script/ScriptLanguageIndex.java +++ b/src/main/java/org/scijava/script/ScriptLanguageIndex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -146,8 +146,8 @@ private boolean put(final String type, final Map map, // Conflicting value; behavior depends on mode. if (gently) { // Do not overwrite the previous value. - if (log != null && log.isWarn()) { - log.warn(overwriteMessage(false, type, key, value, existing)); + if (log != null && log.isDebug()) { + log.debug(overwriteMessage(false, type, key, value, existing)); } return false; } diff --git a/src/main/java/org/scijava/script/ScriptModule.java b/src/main/java/org/scijava/script/ScriptModule.java index f05cbc7ed..87fc5fb0d 100644 --- a/src/main/java/org/scijava/script/ScriptModule.java +++ b/src/main/java/org/scijava/script/ScriptModule.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -102,7 +102,16 @@ public void setErrorWriter(final Writer error) { /** Gets the script engine used to execute the script. */ public ScriptEngine getEngine() { if (scriptEngine == null) { - scriptEngine = getInfo().getLanguage().getScriptEngine(); + final ScriptInfo scriptInfo = getInfo(); + if (scriptInfo == null) { + throw new IllegalArgumentException("Invalid script"); + } + final ScriptLanguage scriptLang = scriptInfo.getLanguage(); + if (scriptLang == null) { + throw new IllegalArgumentException( + "No compatible script language available"); + } + scriptEngine = scriptLang.getScriptEngine(); } return scriptEngine; } diff --git a/src/main/java/org/scijava/script/ScriptREPL.java b/src/main/java/org/scijava/script/ScriptREPL.java index 9c5be1528..ec9e088c4 100644 --- a/src/main/java/org/scijava/script/ScriptREPL.java +++ b/src/main/java/org/scijava/script/ScriptREPL.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,6 +30,7 @@ package org.scijava.script; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -38,6 +39,8 @@ import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; import javax.script.Bindings; import javax.script.ScriptException; @@ -67,9 +70,9 @@ public class ScriptREPL { @Parameter(required = false) private PluginService pluginService; - private final PrintStream out; + private final Consumer out; - private String languagePreference = null; + private String languagePreference; /** List of interpreter-friendly script languages. */ private List languages; @@ -84,19 +87,26 @@ public ScriptREPL(final Context context) { this(context, System.out); } + public ScriptREPL(final Context context, final String language) { + this(context, language, System.out); + } + public ScriptREPL(final Context context, final OutputStream out) { - context.inject(this); - this.out = out instanceof PrintStream ? - (PrintStream) out : new PrintStream(out); + this(context, null, out); } - public ScriptREPL(final Context context, final String language) { - this(context, language, System.out); + public ScriptREPL(final Context context, final String language, + final OutputStream out) + { + this(context, language, outputStreamConsumer(out)); } - public ScriptREPL(final Context context, final String language, final OutputStream out) { - this(context, out); + public ScriptREPL(final Context context, final String language, + final Consumer out) + { + context.inject(this); languagePreference = language; + this.out = out; } /** @@ -132,11 +142,39 @@ public void loop() throws IOException { * @param in Input stream from which commands are read. */ public void loop(final InputStream in) throws IOException { - initialize(); final BufferedReader bin = new BufferedReader(new InputStreamReader(in)); + try { + loop(() -> { + try { + return bin.readLine(); + } + catch (final IOException exc) { + throw new RuntimeException(exc); + } + }); + } + catch (final RuntimeException exc) { + // NB: This convolution lets us throw IOException from inside a + // Supplier.get implementation, by wrapping in a RuntimeException. + // We then unwrap it again and throw it here, where we said we would. + final Throwable cause = exc.getCause(); + if (cause instanceof IOException) throw (IOException) cause; + else throw exc; + } + } + + /** + * Starts a Read-Eval-Print-Loop from the given source, returning when + * the loop terminates. + * + * @param in Source from which commands are read. + */ + public void loop(final Supplier in) { + initialize(); while (true) { prompt(); - final String line = bin.readLine(); + final Object input = in.get(); + final String line = input == null ? null : input.toString(); if (line == null) break; if (!evaluate(line)) return; } @@ -157,54 +195,40 @@ public void initialize() { */ public void initialize(final boolean verbose) { if (verbose) { - out.println("Welcome to the SciJava REPL!"); - out.println(); + println("Welcome to the SciJava REPL!"); + println(); help(); } final List langs = getInterpretedLanguages(); if (verbose) { if (langs.isEmpty()) { - out.println("--------------------------------------------------------------"); - out.println("Uh oh! There are no SciJava script languages available!"); - out.println("Are any on your classpath? E.g.: org.scijava:scripting-groovy?"); - out.println("--------------------------------------------------------------"); - out.println(); + println("--------------------------------------------------------------"); + println("Uh oh! There are no SciJava script languages available!"); + println("Are any on your classpath? E.g.: org.scijava:scripting-groovy?"); + println("--------------------------------------------------------------"); + println(); return; } - out.println("Have fun!"); - out.println(); - - if(languagePreference != null) { - selectPreferredLanguage(langs); - } else { - lang(langs.get(0).getLanguageName()); - } + println("Have fun!"); + println(); } - else if (!langs.isEmpty()) { - if(languagePreference != null) { - selectPreferredLanguage(langs); - } else { - lang(langs.get(0)); - } + if (!langs.isEmpty()) { + if (languagePreference != null) selectPreferredLanguage(langs); + else lang(langs.get(0)); } - populateBindings(interpreter.getBindings()); } private void selectPreferredLanguage(List langs) { - final ScriptLanguage preference = langs - .stream().filter(lang -> languagePreference.equals(lang.getLanguageName())) - .findAny().orElse(null); - if(preference != null) { - lang(preference); - } else { - lang(langs.get(0).getLanguageName()); - } + final ScriptLanguage preference = langs.stream() + .filter(lang -> languagePreference.equals(lang.getLanguageName())) + .findFirst().orElse(langs.get(0)); + lang(preference); } /** Outputs the prompt. */ public void prompt() { - out.print(interpreter == null || interpreter.isReady() ? "> " : "\\ "); + print(interpreter == null || interpreter.isReady() ? "> " : "\\ "); } /** @@ -230,22 +254,22 @@ public boolean evaluate(final String line) { // pass the input to the current interpreter for evaluation final Object result = interpreter.interpret(line); if (result != ScriptInterpreter.MORE_INPUT_PENDING) { - out.println(s(result)); + println(s(result)); } } } catch (final ScriptException exc) { // NB: Something went wrong interpreting the line of code. // Let's just display the error message, unless we are in debug mode. - if (debug) exc.printStackTrace(out); + if (debug) printStackTrace(exc); else { final String msg = exc.getMessage(); - out.println(msg == null ? exc.getClass().getName() : msg); + println(msg == null ? exc.getClass().getName() : msg); } } catch (final Throwable exc) { // NB: Something unusual went wrong. Dump the whole exception always. - exc.printStackTrace(out); + printStackTrace(exc); } return true; } @@ -254,17 +278,17 @@ public boolean evaluate(final String line) { /** Prints a usage guide. */ public void help() { - out.println("Available built-in commands:"); - out.println(); - out.println(" :help | this handy list of commands"); - out.println(" :vars | dump a list of variables"); - out.println(" :lang | switch the active language"); - out.println(" :langs | list available languages"); - out.println(" :debug | toggle full stack traces"); - out.println(" :quit | exit the REPL"); - out.println(); - out.println("Or type a statement to evaluate it with the active language."); - out.println(); + println("Available built-in commands:"); + println(); + println(" :help | this handy list of commands"); + println(" :vars | dump a list of variables"); + println(" :lang | switch the active language"); + println(" :langs | list available languages"); + println(" :debug | toggle full stack traces"); + println(" :quit | exit the REPL"); + println(); + println("Or type a statement to evaluate it with the active language."); + println(); } /** Lists variables in the script context. */ @@ -294,11 +318,11 @@ public void lang(final String langName) { // create the new interpreter final ScriptLanguage language = scriptService.getLanguageByName(langName); if (language == null) { - out.println("No such language: " + langName); + println("No such language: " + langName); return; } lang(language); - out.println("language -> " + interpreter.getLanguage().getLanguageName()); + println("language -> " + interpreter.getLanguage().getLanguageName()); } /** @@ -316,7 +340,7 @@ public void lang(final ScriptLanguage language) { copyBindings(interpreter, newInterpreter); } catch (final Throwable t) { - t.printStackTrace(out); + printStackTrace(t); } interpreter = newInterpreter; } @@ -335,7 +359,7 @@ public void langs() { public void debug() { debug = !debug; - out.println("debug mode -> " + debug); + println("debug mode -> " + debug); } // -- Main method -- @@ -417,7 +441,7 @@ private List gateways() { gateways.add(gateway); } catch (final Throwable t) { - t.printStackTrace(out); + printStackTrace(t); } } return gateways; @@ -442,6 +466,17 @@ private String type(final Object value) { return "[" + decoded.getClass().getName() + "]"; } + private static final String NL = System.getProperty("line.separator"); + private void print(String s) { out.accept(s); } + private void println() { print(NL); } + private void println(final String s) { print(s + NL); } + + private void printStackTrace(final Throwable t) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + t.printStackTrace(new PrintStream(baos)); + println(baos.toString()); + } + private void printColumns(final List... columns) { final int pad = 2; @@ -456,18 +491,28 @@ private void printColumns(final List... columns) { } // output the columns + final StringBuilder sb = new StringBuilder(); for (int i = 0; i < columns[0].size(); i++) { + sb.setLength(0); for (int c = 0; c < columns.length; c++) { final String s = s(columns[c].get(i)); - out.print(s); - for (int p = s.length(); p < widths[c] + pad; p++) { - out.print(' '); + sb.append(s); + if (c < columns.length - 1) { + for (int p = s.length(); p < widths[c] + pad; p++) { + sb.append(' '); + } } } - out.println(); + println(sb.toString()); } } + private static Consumer outputStreamConsumer(final OutputStream out) { + final PrintStream ps = out instanceof PrintStream ? + (PrintStream) out : new PrintStream(out); + return s -> { ps.print(s); ps.flush(); }; + } + private static String lowerCamelCase(final String s) { final StringBuilder sb = new StringBuilder(s); for (int i=0; i "script".equals(directive)); + super("script"::equals); } @Parameter @@ -106,6 +108,9 @@ public ScriptDirectiveScriptProcessor() { @Parameter private ModuleService moduleService; + @Parameter + private ScriptService scriptService; + // -- Internal DirectiveScriptProcessor methods -- @Override @@ -125,6 +130,10 @@ private void assignAttribute(final String k, final Object v) { if (is(k, "name")) info().setName(as(v, String.class)); else if (is(k, "label")) info().setLabel(as(v, String.class)); else if (is(k, "description")) info().setDescription(as(v, String.class)); + else if (is(k, "language")) { + ScriptLanguage lang = parseScriptLanguage(v.toString()); + if (lang != null) info().setLanguage(lang); + } else if (is(k, "menuPath")) { info().setMenuPath(new MenuPath(as(v, String.class))); } @@ -161,4 +170,12 @@ private Double priority(final Object p) { if (lString.matches("last")) return Priority.LAST; return null; } + + private ScriptLanguage parseScriptLanguage(final Object v) { + final String langHint = v.toString(); + ScriptLanguage lang = scriptService.getLanguageByName(langHint); + if (lang == null) lang = scriptService.getLanguageByExtension(langHint); + if (lang == null) log.warn("Unknown script language: " + langHint); + return lang; + } } diff --git a/src/main/java/org/scijava/script/process/ScriptProcessor.java b/src/main/java/org/scijava/script/process/ScriptProcessor.java index e4d86a36e..7e5347932 100644 --- a/src/main/java/org/scijava/script/process/ScriptProcessor.java +++ b/src/main/java/org/scijava/script/process/ScriptProcessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/process/ScriptProcessorService.java b/src/main/java/org/scijava/script/process/ScriptProcessorService.java index 458613b45..e78250b4d 100644 --- a/src/main/java/org/scijava/script/process/ScriptProcessorService.java +++ b/src/main/java/org/scijava/script/process/ScriptProcessorService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/process/ShebangScriptProcessor.java b/src/main/java/org/scijava/script/process/ShebangScriptProcessor.java index 5951b6dbb..188f50906 100644 --- a/src/main/java/org/scijava/script/process/ShebangScriptProcessor.java +++ b/src/main/java/org/scijava/script/process/ShebangScriptProcessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/script/run/ScriptCodeRunner.java b/src/main/java/org/scijava/script/run/ScriptCodeRunner.java index ac6535c89..86c73042b 100644 --- a/src/main/java/org/scijava/script/run/ScriptCodeRunner.java +++ b/src/main/java/org/scijava/script/run/ScriptCodeRunner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/service/AbstractService.java b/src/main/java/org/scijava/service/AbstractService.java index 39062d6a8..d8f3ef1da 100644 --- a/src/main/java/org/scijava/service/AbstractService.java +++ b/src/main/java/org/scijava/service/AbstractService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/service/SciJavaService.java b/src/main/java/org/scijava/service/SciJavaService.java index afcad184a..d252e1b52 100644 --- a/src/main/java/org/scijava/service/SciJavaService.java +++ b/src/main/java/org/scijava/service/SciJavaService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/service/Service.java b/src/main/java/org/scijava/service/Service.java index c11d3c2a8..a7119ba21 100644 --- a/src/main/java/org/scijava/service/Service.java +++ b/src/main/java/org/scijava/service/Service.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/service/ServiceHelper.java b/src/main/java/org/scijava/service/ServiceHelper.java index 0e8db19d6..0cf2a21ed 100644 --- a/src/main/java/org/scijava/service/ServiceHelper.java +++ b/src/main/java/org/scijava/service/ServiceHelper.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/service/ServiceIndex.java b/src/main/java/org/scijava/service/ServiceIndex.java index 9632da00d..910c6273d 100644 --- a/src/main/java/org/scijava/service/ServiceIndex.java +++ b/src/main/java/org/scijava/service/ServiceIndex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/service/event/ServicesLoadedEvent.java b/src/main/java/org/scijava/service/event/ServicesLoadedEvent.java index 0a9e58c27..e2fc6e3fe 100644 --- a/src/main/java/org/scijava/service/event/ServicesLoadedEvent.java +++ b/src/main/java/org/scijava/service/event/ServicesLoadedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/startup/DefaultStartupService.java b/src/main/java/org/scijava/startup/DefaultStartupService.java index 4104c3d19..d3b253a58 100644 --- a/src/main/java/org/scijava/startup/DefaultStartupService.java +++ b/src/main/java/org/scijava/startup/DefaultStartupService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/startup/StartupService.java b/src/main/java/org/scijava/startup/StartupService.java index 1dc08a2ee..6446b3447 100644 --- a/src/main/java/org/scijava/startup/StartupService.java +++ b/src/main/java/org/scijava/startup/StartupService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/task/DefaultTask.java b/src/main/java/org/scijava/task/DefaultTask.java index 44f1c3b30..310dd8f15 100644 --- a/src/main/java/org/scijava/task/DefaultTask.java +++ b/src/main/java/org/scijava/task/DefaultTask.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,9 +39,9 @@ * Default implementation of {@link Task}. Throughout the task (or job), * {@link Task#setProgressValue(long)} can be called to inform * how the job is progressing. - * + *

* Asynchronous case: - * - A job (runnable) is sent for execution to the linked {@link ThreadService}. + * A job (runnable) is sent for execution to the linked {@link ThreadService}. * It reports status updates via the linked {@link EventService}. * A {@link org.scijava.task.event.TaskEvent} is sent before the job * is started and when finished. @@ -50,9 +50,10 @@ * by calling {@link Future#cancel(boolean)}. * This default behaviour can be supplemented by an additional * custom callback which can be set in {@link Task#setCancelCallBack(Runnable)}. - * + *

+ *

* Synchronous case: - * - A job that reports its status in between calls of {@link Task#start()}, + * A job that reports its status in between calls of {@link Task#start()}, * and {@link Task#finish()}. It also reports its status via * the linked {@link EventService}. * Start and finish calls allow publishing proper {@link org.scijava.task.event.TaskEvent} @@ -60,8 +61,10 @@ * Upon cancellation of a synchronous task, it is the responsibility * of the synchronous task to handle its own cancellation through * a custom callback which can be set via {@link Task#setCancelCallBack(Runnable)}. + *

* - * @author Curtis Rueden, Nicolas Chiaruttini + * @author Curtis Rueden + * @author Nicolas Chiaruttini */ public class DefaultTask implements Task { diff --git a/src/main/java/org/scijava/task/DefaultTaskService.java b/src/main/java/org/scijava/task/DefaultTaskService.java index 09375262a..7a2016f51 100644 --- a/src/main/java/org/scijava/task/DefaultTaskService.java +++ b/src/main/java/org/scijava/task/DefaultTaskService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/task/Task.java b/src/main/java/org/scijava/task/Task.java index 7e6b66062..1dd539ab5 100644 --- a/src/main/java/org/scijava/task/Task.java +++ b/src/main/java/org/scijava/task/Task.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/task/TaskService.java b/src/main/java/org/scijava/task/TaskService.java index 887acf804..d3a46b7f9 100644 --- a/src/main/java/org/scijava/task/TaskService.java +++ b/src/main/java/org/scijava/task/TaskService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/task/event/TaskEvent.java b/src/main/java/org/scijava/task/event/TaskEvent.java index 79d55f7d2..bb4cfb4dd 100644 --- a/src/main/java/org/scijava/task/event/TaskEvent.java +++ b/src/main/java/org/scijava/task/event/TaskEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/test/TestUtils.java b/src/main/java/org/scijava/test/TestUtils.java index 7f9c63075..fd4ed17c7 100644 --- a/src/main/java/org/scijava/test/TestUtils.java +++ b/src/main/java/org/scijava/test/TestUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/text/AbstractTextFormat.java b/src/main/java/org/scijava/text/AbstractTextFormat.java index 202092996..f07498edd 100644 --- a/src/main/java/org/scijava/text/AbstractTextFormat.java +++ b/src/main/java/org/scijava/text/AbstractTextFormat.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,5 +41,14 @@ public abstract class AbstractTextFormat extends AbstractHandlerPlugin implements TextFormat { - // NB: No implementation needed. + // -- Typed methods -- + + @Override + public boolean supports(final File data) { + // NB: This override is necessary, because the default super is + // AbstractHandlerPlugin->AbstractTypedPlugin->TypedPlugin->Typed, + // which fails to invoke the needed TextFormat.super. + // See fiji/fiji#303 and fiji/HDF5_Vibez#18. + return TextFormat.super.supports(data); + } } diff --git a/src/main/java/org/scijava/text/DefaultTextService.java b/src/main/java/org/scijava/text/DefaultTextService.java index dab8a2898..9a562a334 100644 --- a/src/main/java/org/scijava/text/DefaultTextService.java +++ b/src/main/java/org/scijava/text/DefaultTextService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -59,7 +59,7 @@ public final class DefaultTextService extends @Override public String open(final File file) throws IOException { - // This routine is from: http://stackoverflow.com/a/326440 + // This routine is from: https://stackoverflow.com/a/326440 try (final FileInputStream stream = new FileInputStream(file)) { final FileChannel fc = stream.getChannel(); final MappedByteBuffer bb = diff --git a/src/main/java/org/scijava/text/TextFormat.java b/src/main/java/org/scijava/text/TextFormat.java index 40a314e8a..66f5fc405 100644 --- a/src/main/java/org/scijava/text/TextFormat.java +++ b/src/main/java/org/scijava/text/TextFormat.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -63,6 +63,7 @@ public interface TextFormat extends HandlerPlugin { @Override default boolean supports(final File file) { + if (!HandlerPlugin.super.supports(file)) return false; for (final String ext : getExtensions()) { if (FileUtils.getExtension(file).equalsIgnoreCase(ext)) return true; } diff --git a/src/main/java/org/scijava/text/TextService.java b/src/main/java/org/scijava/text/TextService.java index 8f640ba5f..6884d700f 100644 --- a/src/main/java/org/scijava/text/TextService.java +++ b/src/main/java/org/scijava/text/TextService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/text/io/DefaultTextIOService.java b/src/main/java/org/scijava/text/io/DefaultTextIOService.java index b1c9ad530..a16fc1933 100644 --- a/src/main/java/org/scijava/text/io/DefaultTextIOService.java +++ b/src/main/java/org/scijava/text/io/DefaultTextIOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/text/io/TextIOPlugin.java b/src/main/java/org/scijava/text/io/TextIOPlugin.java index 04018a44f..cd4d4e5c4 100644 --- a/src/main/java/org/scijava/text/io/TextIOPlugin.java +++ b/src/main/java/org/scijava/text/io/TextIOPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/text/io/TextIOService.java b/src/main/java/org/scijava/text/io/TextIOService.java index 42e36e64a..d21d11c87 100644 --- a/src/main/java/org/scijava/text/io/TextIOService.java +++ b/src/main/java/org/scijava/text/io/TextIOService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/thread/DefaultThreadService.java b/src/main/java/org/scijava/thread/DefaultThreadService.java index 3262ee21d..121dc74e1 100644 --- a/src/main/java/org/scijava/thread/DefaultThreadService.java +++ b/src/main/java/org/scijava/thread/DefaultThreadService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,6 +39,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import org.scijava.log.LogService; import org.scijava.plugin.Parameter; @@ -58,6 +59,8 @@ public final class DefaultThreadService extends AbstractService implements private static final String SCIJAVA_THREAD_PREFIX = "SciJava-"; + private static final long SHUTDOWN_TIMEOUT = 5000; + private static WeakHashMap parents = new WeakHashMap<>(); @@ -159,11 +162,23 @@ public synchronized void dispose() { disposed = true; if (executor != null) { executor.shutdown(); + try { + executor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS); + } + catch (final InterruptedException exc) { + log.debug(exc); + } executor = null; } if (queues != null) { for (final ExecutorService queue : queues.values()) { queue.shutdown(); + try { + queue.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS); + } + catch (final InterruptedException exc) { + log.debug(exc); + } } } } @@ -173,7 +188,14 @@ public synchronized void dispose() { @Override public Thread newThread(final Runnable r) { final String threadName = contextThreadPrefix() + nextThread++; - return new Thread(r, threadName); + final Thread thread = new Thread(r, threadName); + // NB: Use daemon threads for the thread pool, so that idling threads do + // not prevent the JVM shutdown sequence from starting. The application + // context, and therefore the thread service, will try to dispose itself + // upon JVM shutdown, which will invoke executor.awaitTermination(), so + // there will be a chance for these threads to complete any pending work. + thread.setDaemon(true); + return thread; } // -- Helper methods -- diff --git a/src/main/java/org/scijava/thread/ThreadService.java b/src/main/java/org/scijava/thread/ThreadService.java index afddb6f8f..3531fc2a3 100644 --- a/src/main/java/org/scijava/thread/ThreadService.java +++ b/src/main/java/org/scijava/thread/ThreadService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/AbstractTool.java b/src/main/java/org/scijava/tool/AbstractTool.java index 054fd1a8b..35f3d0d0d 100644 --- a/src/main/java/org/scijava/tool/AbstractTool.java +++ b/src/main/java/org/scijava/tool/AbstractTool.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/CustomDrawnTool.java b/src/main/java/org/scijava/tool/CustomDrawnTool.java index 3a3905780..b7e766542 100644 --- a/src/main/java/org/scijava/tool/CustomDrawnTool.java +++ b/src/main/java/org/scijava/tool/CustomDrawnTool.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/DefaultToolService.java b/src/main/java/org/scijava/tool/DefaultToolService.java index d78e1a53a..a8ae89fe7 100644 --- a/src/main/java/org/scijava/tool/DefaultToolService.java +++ b/src/main/java/org/scijava/tool/DefaultToolService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/DummyTool.java b/src/main/java/org/scijava/tool/DummyTool.java index baef6dfe3..f8b90807e 100644 --- a/src/main/java/org/scijava/tool/DummyTool.java +++ b/src/main/java/org/scijava/tool/DummyTool.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/IconDrawer.java b/src/main/java/org/scijava/tool/IconDrawer.java index 0d1b45824..1c4778eb1 100644 --- a/src/main/java/org/scijava/tool/IconDrawer.java +++ b/src/main/java/org/scijava/tool/IconDrawer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/IconService.java b/src/main/java/org/scijava/tool/IconService.java index 43ac9f66f..8c7473dcb 100644 --- a/src/main/java/org/scijava/tool/IconService.java +++ b/src/main/java/org/scijava/tool/IconService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/Tool.java b/src/main/java/org/scijava/tool/Tool.java index cadfcf115..b42af857e 100644 --- a/src/main/java/org/scijava/tool/Tool.java +++ b/src/main/java/org/scijava/tool/Tool.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/ToolService.java b/src/main/java/org/scijava/tool/ToolService.java index a254a91e3..061f3fed4 100644 --- a/src/main/java/org/scijava/tool/ToolService.java +++ b/src/main/java/org/scijava/tool/ToolService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/event/ToolActivatedEvent.java b/src/main/java/org/scijava/tool/event/ToolActivatedEvent.java index 5142bbe18..3ab52fca2 100644 --- a/src/main/java/org/scijava/tool/event/ToolActivatedEvent.java +++ b/src/main/java/org/scijava/tool/event/ToolActivatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/event/ToolDeactivatedEvent.java b/src/main/java/org/scijava/tool/event/ToolDeactivatedEvent.java index 7503eed17..fc61e8332 100644 --- a/src/main/java/org/scijava/tool/event/ToolDeactivatedEvent.java +++ b/src/main/java/org/scijava/tool/event/ToolDeactivatedEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/tool/event/ToolEvent.java b/src/main/java/org/scijava/tool/event/ToolEvent.java index 6c6f1f185..f55392dc8 100644 --- a/src/main/java/org/scijava/tool/event/ToolEvent.java +++ b/src/main/java/org/scijava/tool/event/ToolEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/ARGBPlane.java b/src/main/java/org/scijava/ui/ARGBPlane.java index 5d7678f61..7d158e366 100644 --- a/src/main/java/org/scijava/ui/ARGBPlane.java +++ b/src/main/java/org/scijava/ui/ARGBPlane.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/AbstractInputHarvesterPlugin.java b/src/main/java/org/scijava/ui/AbstractInputHarvesterPlugin.java index 9d12ab82f..71afdf0cc 100644 --- a/src/main/java/org/scijava/ui/AbstractInputHarvesterPlugin.java +++ b/src/main/java/org/scijava/ui/AbstractInputHarvesterPlugin.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/AbstractUIInputWidget.java b/src/main/java/org/scijava/ui/AbstractUIInputWidget.java index 394ec8829..04561a123 100644 --- a/src/main/java/org/scijava/ui/AbstractUIInputWidget.java +++ b/src/main/java/org/scijava/ui/AbstractUIInputWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/AbstractUserInterface.java b/src/main/java/org/scijava/ui/AbstractUserInterface.java index 0c3e22da5..8b5e426a5 100644 --- a/src/main/java/org/scijava/ui/AbstractUserInterface.java +++ b/src/main/java/org/scijava/ui/AbstractUserInterface.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -79,6 +79,7 @@ public abstract class AbstractUserInterface extends AbstractRichPlugin @Override public void show() { + if (visible) return; createUI(); visible = true; } diff --git a/src/main/java/org/scijava/ui/ApplicationFrame.java b/src/main/java/org/scijava/ui/ApplicationFrame.java index dbda0cc80..571ab621e 100644 --- a/src/main/java/org/scijava/ui/ApplicationFrame.java +++ b/src/main/java/org/scijava/ui/ApplicationFrame.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/Arrangeable.java b/src/main/java/org/scijava/ui/Arrangeable.java index fb5a06dff..1b92b5768 100644 --- a/src/main/java/org/scijava/ui/Arrangeable.java +++ b/src/main/java/org/scijava/ui/Arrangeable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/CloseConfirmable.java b/src/main/java/org/scijava/ui/CloseConfirmable.java index 56450088f..73e657b63 100644 --- a/src/main/java/org/scijava/ui/CloseConfirmable.java +++ b/src/main/java/org/scijava/ui/CloseConfirmable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/DefaultUIService.java b/src/main/java/org/scijava/ui/DefaultUIService.java index 42899053b..7c8103a4c 100644 --- a/src/main/java/org/scijava/ui/DefaultUIService.java +++ b/src/main/java/org/scijava/ui/DefaultUIService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,8 +29,10 @@ package org.scijava.ui; +import java.awt.GraphicsEnvironment; import java.io.File; import java.io.FileFilter; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -116,6 +118,9 @@ public final class DefaultUIService extends AbstractService implements /** The default user interface to use, if one is not explicitly specified. */ private UserInterface defaultUI; + /** The last UI used when performing UI operations via the service. */ + private UserInterface activeUI; + /** * When true, {@link #isHeadless()} will return true regardless of the value * of the {@code java.awt.headless} system property. When false, {@link @@ -142,18 +147,12 @@ public void addUI(final String name, final UserInterface ui) { @Override public void showUI() { if (disposed) return; - final UserInterface ui = getDefaultUI(); - if (ui == null) { - throw new IllegalStateException("No UIs available. " + - "Please add a component containing a UIPlugin " + - "(e.g., scijava-ui-swing) to your class-path."); - } - showUI(ui); + showUI(activeUI()); } @Override public void showUI(final String name) { - final UserInterface ui = uiMap().get(name); + final UserInterface ui = getUI(name); if (ui == null) { throw new IllegalArgumentException("No such user interface: " + name); } @@ -163,24 +162,37 @@ public void showUI(final String name) { @Override public void showUI(final UserInterface ui) { log.debug("Launching user interface: " + ui.getClass().getName()); - ui.show(); - // NB: Also show all the current displays. - for (final Display display : displayService.getDisplays()) { - ui.show(display); + Runnable showUI = () -> { + ui.show(); + // NB: Also show all the current displays. + for (final Display display : displayService.getDisplays()) { + ui.show(display); + } + }; + + // Dispatch on EDT if necessary + if (ui.requiresEDT()) { + try { + threadService.invoke(showUI); + } + catch (InterruptedException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + else { + showUI.run(); } eventService.publish(new UIShownEvent(ui)); } @Override public boolean isVisible() { - final UserInterface ui = getDefaultUI(); - if (ui == null) return false; - return ui.isVisible(); + return activeUI().isVisible(); } @Override public boolean isVisible(final String name) { - final UserInterface ui = uiMap().get(name); + final UserInterface ui = getUI(name); return ui != null && ui.isVisible(); } @@ -191,15 +203,15 @@ public void setHeadless(final boolean headless) { @Override public boolean isHeadless() { - // NB: We do not use java.awt.GraphicsConfiguration.isHeadless() - // because scijava-common eschews java.awt.* classes when possible. - return forceHeadless || Boolean.getBoolean("java.awt.headless"); + return forceHeadless || + Boolean.getBoolean("java.awt.headless") || + GraphicsEnvironment.isHeadless(); } @Override public UserInterface getDefaultUI() { if (!initialized) discoverUIs(); - if (isHeadless()) return uiMap().get(HeadlessUI.NAME); + if (isHeadless()) return getUI(HeadlessUI.NAME); if (defaultUI != null) return defaultUI; return uiList().isEmpty() ? null : uiList().get(0); } @@ -243,17 +255,17 @@ public List>> getViewerPlugins() { @Override public void show(final Object o) { - getDefaultUI().show(o); + activeUI().show(o); } @Override public void show(final String name, final Object o) { - getDefaultUI().show(name, o); + activeUI().show(name, o); } @Override public void show(final Display display) { - getDefaultUI().show(display); + activeUI().show(display); } @Override @@ -308,45 +320,38 @@ public DialogPrompt.Result showDialog(final String message, final String title, final DialogPrompt.MessageType messageType, final DialogPrompt.OptionType optionType) { - final UserInterface ui = getDefaultUI(); - if (ui == null) return null; - final DialogPrompt dialogPrompt = - ui.dialogPrompt(message, title, messageType, optionType); + final DialogPrompt dialogPrompt = // + activeUI().dialogPrompt(message, title, messageType, optionType); return dialogPrompt == null ? null : dialogPrompt.prompt(); } @Override public File chooseFile(final File file, final String style) { - final UserInterface ui = getDefaultUI(); - return ui == null ? null : ui.chooseFile(file, style); + return activeUI().chooseFile(file, style); } @Override public File chooseFile(final String title, final File file, final String style) { - final UserInterface ui = getDefaultUI(); - return ui == null ? null : ui.chooseFile(title, file, style); + return activeUI().chooseFile(title, file, style); } @Override public File[] chooseFiles(File parent, File[] files, FileFilter filter, String style) { - final UserInterface ui = getDefaultUI(); - return ui == null ? null : ui.chooseFiles(parent, files, filter, style); + return activeUI().chooseFiles(parent, files, filter, style); } @Override public List chooseFiles(File parent, List fileList, FileFilter filter, String style) { - final UserInterface ui = getDefaultUI(); - return ui == null ? null : ui.chooseFiles(parent, fileList, filter, style); + return activeUI().chooseFiles(parent, fileList, filter, style); } @Override public void showContextMenu(final String menuRoot, final Display display, final int x, final int y) { - final UserInterface ui = getDefaultUI(); - if (ui != null) ui.showContextMenu(menuRoot, display, x, y); + activeUI().showContextMenu(menuRoot, display, x, y); } @Override @@ -541,4 +546,17 @@ private void addUserInterface(final String name, final UserInterface ui) { private String getTitle() { return appService.getApp().getTitle(); } + + /** Gets the UI to use when performing UI operations via the service. */ + private UserInterface activeUI() { + // If a particular UI is already active and still visible, use that one. + if (activeUI != null && activeUI.isVisible()) return activeUI; + + // If a UI is visible, use it. + final List visibleUIs = getVisibleUIs(); + if (visibleUIs.size() > 0) return activeUI = visibleUIs.get(0); + + // No UI is visible, so use the default one. + return activeUI = getDefaultUI(); + } } diff --git a/src/main/java/org/scijava/ui/Desktop.java b/src/main/java/org/scijava/ui/Desktop.java index bfca746d9..4e39f09dd 100644 --- a/src/main/java/org/scijava/ui/Desktop.java +++ b/src/main/java/org/scijava/ui/Desktop.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/DialogPrompt.java b/src/main/java/org/scijava/ui/DialogPrompt.java index 26c0ede95..0f598875a 100644 --- a/src/main/java/org/scijava/ui/DialogPrompt.java +++ b/src/main/java/org/scijava/ui/DialogPrompt.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/FileListPreprocessor.java b/src/main/java/org/scijava/ui/FileListPreprocessor.java index 13d8feb68..9d8da8f0b 100644 --- a/src/main/java/org/scijava/ui/FileListPreprocessor.java +++ b/src/main/java/org/scijava/ui/FileListPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/FilePreprocessor.java b/src/main/java/org/scijava/ui/FilePreprocessor.java index d03e43bc4..0e4a52d97 100644 --- a/src/main/java/org/scijava/ui/FilePreprocessor.java +++ b/src/main/java/org/scijava/ui/FilePreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/StatusBar.java b/src/main/java/org/scijava/ui/StatusBar.java index 9b6b71377..009a5a7e0 100644 --- a/src/main/java/org/scijava/ui/StatusBar.java +++ b/src/main/java/org/scijava/ui/StatusBar.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/SystemClipboard.java b/src/main/java/org/scijava/ui/SystemClipboard.java index 8eb4e8bf6..a2f5b2c59 100644 --- a/src/main/java/org/scijava/ui/SystemClipboard.java +++ b/src/main/java/org/scijava/ui/SystemClipboard.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/ToolBar.java b/src/main/java/org/scijava/ui/ToolBar.java index 95a137aa5..289dbc8b4 100644 --- a/src/main/java/org/scijava/ui/ToolBar.java +++ b/src/main/java/org/scijava/ui/ToolBar.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/UIPreprocessor.java b/src/main/java/org/scijava/ui/UIPreprocessor.java index 87a755a14..d9af6ebca 100644 --- a/src/main/java/org/scijava/ui/UIPreprocessor.java +++ b/src/main/java/org/scijava/ui/UIPreprocessor.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/UIService.java b/src/main/java/org/scijava/ui/UIService.java index d3111bb3e..a86652b8e 100644 --- a/src/main/java/org/scijava/ui/UIService.java +++ b/src/main/java/org/scijava/ui/UIService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -106,7 +106,7 @@ public interface UIService extends SciJavaService { *

* Note that if the system itself is headless—which can be detected via * the {@code java.awt.headless} system property or by calling - * {@code java.awt.GraphicsEnvironment.isHeadless()}—then calling + * {@link java.awt.GraphicsEnvironment#isHeadless()}—then calling * {@code setHeadless(false)} will have no effect; the system will still be * headless, and {@link #isHeadless()} will still return true. *

@@ -119,7 +119,15 @@ public interface UIService extends SciJavaService { */ void setHeadless(boolean isHeadless); - /** Gets whether the UI is running in headless mode (no UI). */ + /** + * Gets whether the UI is running in headless mode (no UI). + *

+ * More precisely: returns true when {@code java.awt.headless} system + * property is set, and/or {@link java.awt.GraphicsEnvironment#isHeadless()} + * returns true, and/or {@link #setHeadless(boolean)} was called with {@code + * true} to force headless behavior in an otherwise headful environment. + *

+ */ boolean isHeadless(); /** diff --git a/src/main/java/org/scijava/ui/UserInterface.java b/src/main/java/org/scijava/ui/UserInterface.java index 162532dac..c2808bdc1 100644 --- a/src/main/java/org/scijava/ui/UserInterface.java +++ b/src/main/java/org/scijava/ui/UserInterface.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,6 +41,7 @@ import org.scijava.ui.console.ConsolePane; import org.scijava.ui.viewer.DisplayWindow; import org.scijava.widget.FileWidget; +import org.scijava.widget.WidgetStyle; /** * An end-user SciJava application user interface. @@ -160,11 +161,11 @@ DialogPrompt dialogPrompt(String message, String title, default File chooseFile(final File file, final String style) { final String title; // style can be a string with multiple comma-separated keywords - // TODO use a utility class for style handling, e.g. StyleUtils.isStyle(style, ...) if (style == null) title = "Choose a file"; - else if (style.toLowerCase().contains(FileWidget.DIRECTORY_STYLE)) title = "Choose a directory"; - else if (style.toLowerCase().contains(FileWidget.OPEN_STYLE)) title = "Open"; - else if (style.toLowerCase().contains(FileWidget.SAVE_STYLE)) title = "Save"; + else if (WidgetStyle.isStyle(style, FileWidget.DIRECTORY_STYLE)) title = "Choose a directory"; + else if (WidgetStyle.isStyle(style, FileWidget.FILE_AND_DIRECTORY_STYLE)) title = "Choose a file or directory"; + else if (WidgetStyle.isStyle(style, FileWidget.OPEN_STYLE)) title = "Open"; + else if (WidgetStyle.isStyle(style, FileWidget.SAVE_STYLE)) title = "Save"; else title = "Choose a file"; return chooseFile(title, file, style); @@ -180,6 +181,7 @@ default File chooseFile(final File file, final String style) { *
  • {@link FileWidget#OPEN_STYLE}
  • *
  • {@link FileWidget#SAVE_STYLE}
  • *
  • {@link FileWidget#DIRECTORY_STYLE}
  • + *
  • {@link FileWidget#FILE_AND_DIRECTORY_STYLE}
  • * * @return The {@link File} chosen by the user, or null if prompt is not * available diff --git a/src/main/java/org/scijava/ui/console/AbstractConsolePane.java b/src/main/java/org/scijava/ui/console/AbstractConsolePane.java index db4817ceb..1657a42e4 100644 --- a/src/main/java/org/scijava/ui/console/AbstractConsolePane.java +++ b/src/main/java/org/scijava/ui/console/AbstractConsolePane.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/console/ConsolePane.java b/src/main/java/org/scijava/ui/console/ConsolePane.java index 7145ed54a..de3c876b0 100644 --- a/src/main/java/org/scijava/ui/console/ConsolePane.java +++ b/src/main/java/org/scijava/ui/console/ConsolePane.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/console/HeadlessArgument.java b/src/main/java/org/scijava/ui/console/HeadlessArgument.java index 3a10f459d..821dd516e 100644 --- a/src/main/java/org/scijava/ui/console/HeadlessArgument.java +++ b/src/main/java/org/scijava/ui/console/HeadlessArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/console/ShowUIArgument.java b/src/main/java/org/scijava/ui/console/ShowUIArgument.java index 9d0c1161b..00b7a192f 100644 --- a/src/main/java/org/scijava/ui/console/ShowUIArgument.java +++ b/src/main/java/org/scijava/ui/console/ShowUIArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/console/UIArgument.java b/src/main/java/org/scijava/ui/console/UIArgument.java index 0deeba42b..8f962fbe7 100644 --- a/src/main/java/org/scijava/ui/console/UIArgument.java +++ b/src/main/java/org/scijava/ui/console/UIArgument.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropData.java b/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropData.java index 09e3efb79..0e9d59514 100644 --- a/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropData.java +++ b/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropData.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropHandler.java b/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropHandler.java index 05d350bd7..77bf71ca0 100644 --- a/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropHandler.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropData.java b/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropData.java index 0529ea7c5..e6095d0ea 100644 --- a/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropData.java +++ b/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropData.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropService.java b/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropService.java index 524f5a887..4b36ad97d 100644 --- a/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropService.java +++ b/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/DragAndDropData.java b/src/main/java/org/scijava/ui/dnd/DragAndDropData.java index d5924bbbc..2d3c6f856 100644 --- a/src/main/java/org/scijava/ui/dnd/DragAndDropData.java +++ b/src/main/java/org/scijava/ui/dnd/DragAndDropData.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/DragAndDropHandler.java b/src/main/java/org/scijava/ui/dnd/DragAndDropHandler.java index 4f7d47043..419ef09e6 100644 --- a/src/main/java/org/scijava/ui/dnd/DragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/DragAndDropHandler.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/DragAndDropService.java b/src/main/java/org/scijava/ui/dnd/DragAndDropService.java index a7b394407..d63c06e53 100644 --- a/src/main/java/org/scijava/ui/dnd/DragAndDropService.java +++ b/src/main/java/org/scijava/ui/dnd/DragAndDropService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/FileDragAndDropHandler.java b/src/main/java/org/scijava/ui/dnd/FileDragAndDropHandler.java index 11aa98108..4e16054f7 100644 --- a/src/main/java/org/scijava/ui/dnd/FileDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/FileDragAndDropHandler.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java b/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java index 9ca0833ca..0057d863e 100644 --- a/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/MIMEType.java b/src/main/java/org/scijava/ui/dnd/MIMEType.java index c5fd7ec61..71e1f13f1 100644 --- a/src/main/java/org/scijava/ui/dnd/MIMEType.java +++ b/src/main/java/org/scijava/ui/dnd/MIMEType.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/ScriptFileDragAndDropHandler.java b/src/main/java/org/scijava/ui/dnd/ScriptFileDragAndDropHandler.java index a798ff7ec..f456671ae 100644 --- a/src/main/java/org/scijava/ui/dnd/ScriptFileDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/ScriptFileDragAndDropHandler.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/event/DragAndDropEvent.java b/src/main/java/org/scijava/ui/dnd/event/DragAndDropEvent.java index 20c240ead..4aecd6b8b 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragAndDropEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragAndDropEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/event/DragEnterEvent.java b/src/main/java/org/scijava/ui/dnd/event/DragEnterEvent.java index f219555ab..7b09815ba 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragEnterEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragEnterEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/event/DragExitEvent.java b/src/main/java/org/scijava/ui/dnd/event/DragExitEvent.java index fbe9b6ce1..5f07f0b9d 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragExitEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragExitEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/event/DragOverEvent.java b/src/main/java/org/scijava/ui/dnd/event/DragOverEvent.java index f0376b017..7baeaa77e 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragOverEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragOverEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/dnd/event/DropEvent.java b/src/main/java/org/scijava/ui/dnd/event/DropEvent.java index 0fd7677e6..2775e56f0 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DropEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DropEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/event/UIEvent.java b/src/main/java/org/scijava/ui/event/UIEvent.java index 0f4e3a9b0..84a32ed63 100644 --- a/src/main/java/org/scijava/ui/event/UIEvent.java +++ b/src/main/java/org/scijava/ui/event/UIEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/event/UIShownEvent.java b/src/main/java/org/scijava/ui/event/UIShownEvent.java index d7b893f3c..2de7f2685 100644 --- a/src/main/java/org/scijava/ui/event/UIShownEvent.java +++ b/src/main/java/org/scijava/ui/event/UIShownEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java b/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java index 3352913e3..dc65aae76 100644 --- a/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java +++ b/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/headless/HeadlessUI.java b/src/main/java/org/scijava/ui/headless/HeadlessUI.java index c8aceb5ae..04536a6c0 100644 --- a/src/main/java/org/scijava/ui/headless/HeadlessUI.java +++ b/src/main/java/org/scijava/ui/headless/HeadlessUI.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java b/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java index 96f51ff72..d473685b3 100644 --- a/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java +++ b/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/viewer/AbstractDisplayViewer.java b/src/main/java/org/scijava/ui/viewer/AbstractDisplayViewer.java index 35cefdadc..418f43830 100644 --- a/src/main/java/org/scijava/ui/viewer/AbstractDisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/AbstractDisplayViewer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/viewer/DisplayPanel.java b/src/main/java/org/scijava/ui/viewer/DisplayPanel.java index f438822c0..3f88949e4 100644 --- a/src/main/java/org/scijava/ui/viewer/DisplayPanel.java +++ b/src/main/java/org/scijava/ui/viewer/DisplayPanel.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/viewer/DisplayViewer.java b/src/main/java/org/scijava/ui/viewer/DisplayViewer.java index 657e860b5..9698cb56e 100644 --- a/src/main/java/org/scijava/ui/viewer/DisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/DisplayViewer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/viewer/DisplayWindow.java b/src/main/java/org/scijava/ui/viewer/DisplayWindow.java index d9d4945c4..c6397ed6e 100644 --- a/src/main/java/org/scijava/ui/viewer/DisplayWindow.java +++ b/src/main/java/org/scijava/ui/viewer/DisplayWindow.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/viewer/text/AbstractTextDisplayViewer.java b/src/main/java/org/scijava/ui/viewer/text/AbstractTextDisplayViewer.java index 2b6e93004..e19a33e18 100644 --- a/src/main/java/org/scijava/ui/viewer/text/AbstractTextDisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/text/AbstractTextDisplayViewer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/viewer/text/TextDisplayPanel.java b/src/main/java/org/scijava/ui/viewer/text/TextDisplayPanel.java index 3f0ba3fec..107d46aa8 100644 --- a/src/main/java/org/scijava/ui/viewer/text/TextDisplayPanel.java +++ b/src/main/java/org/scijava/ui/viewer/text/TextDisplayPanel.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/ui/viewer/text/TextDisplayViewer.java b/src/main/java/org/scijava/ui/viewer/text/TextDisplayViewer.java index 302a6f41a..4efb2adb1 100644 --- a/src/main/java/org/scijava/ui/viewer/text/TextDisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/text/TextDisplayViewer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/AbstractPrimitiveArray.java b/src/main/java/org/scijava/util/AbstractPrimitiveArray.java index 735f286b0..6b284c0c3 100644 --- a/src/main/java/org/scijava/util/AbstractPrimitiveArray.java +++ b/src/main/java/org/scijava/util/AbstractPrimitiveArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/AppUtils.java b/src/main/java/org/scijava/util/AppUtils.java index e83e06798..134aa2ac4 100644 --- a/src/main/java/org/scijava/util/AppUtils.java +++ b/src/main/java/org/scijava/util/AppUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -130,7 +130,7 @@ public static File getBaseDirectory(final Class c) { public static File getBaseDirectory(final Class c, final String baseSubdirectory) { - // see: http://stackoverflow.com/a/12733172/1207769 + // see: https://stackoverflow.com/a/12733172/1207769 // step 1: convert Class to URL final URL location = Types.location(c); @@ -171,7 +171,7 @@ public static File getBaseDirectory(final Class c, * this cache is located in {@code ~/.m2/repository}. The location will be * {@code groupId/artifactId/version/artifactId-version.jar} where * {@code groupId}, {@code artifactId} and {@code version} are the Maven GAV + * href="https://maven.apache.org/pom.html#Maven_Coordinates">Maven GAV * coordinates. Note that in this case, no base directory with respect to * the given class can be found, and this method will return null. *
  • Within a JAR file beneath the base directory. Common cases diff --git a/src/main/java/org/scijava/util/ArrayUtils.java b/src/main/java/org/scijava/util/ArrayUtils.java index c6487c5cf..42afdfbcb 100644 --- a/src/main/java/org/scijava/util/ArrayUtils.java +++ b/src/main/java/org/scijava/util/ArrayUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -88,7 +88,7 @@ public static T[] array(final T... values) { * object is an array type, a {@link PrimitiveArray} wrapper will be created. */ public static Collection toCollection(final Object value) { - // If the value is null or we we have a collection, just return it + // If the value is null or we have a collection, just return it if (value == null || Collection.class.isAssignableFrom(value.getClass())) { return (Collection) value; } diff --git a/src/main/java/org/scijava/util/BoolArray.java b/src/main/java/org/scijava/util/BoolArray.java index 72e192bbe..d0d6589b7 100644 --- a/src/main/java/org/scijava/util/BoolArray.java +++ b/src/main/java/org/scijava/util/BoolArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ByteArray.java b/src/main/java/org/scijava/util/ByteArray.java index f1e831c0e..ad092abb5 100644 --- a/src/main/java/org/scijava/util/ByteArray.java +++ b/src/main/java/org/scijava/util/ByteArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Bytes.java b/src/main/java/org/scijava/util/Bytes.java index fbce5e167..5b56f8d03 100644 --- a/src/main/java/org/scijava/util/Bytes.java +++ b/src/main/java/org/scijava/util/Bytes.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/CharArray.java b/src/main/java/org/scijava/util/CharArray.java index bfe0ae73e..8459597da 100644 --- a/src/main/java/org/scijava/util/CharArray.java +++ b/src/main/java/org/scijava/util/CharArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/CheckSezpoz.java b/src/main/java/org/scijava/util/CheckSezpoz.java index 459260f05..d5f384f9e 100644 --- a/src/main/java/org/scijava/util/CheckSezpoz.java +++ b/src/main/java/org/scijava/util/CheckSezpoz.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ClassUtils.java b/src/main/java/org/scijava/util/ClassUtils.java index d9d3b2f67..e9e7e4dc0 100644 --- a/src/main/java/org/scijava/util/ClassUtils.java +++ b/src/main/java/org/scijava/util/ClassUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ColorRGB.java b/src/main/java/org/scijava/util/ColorRGB.java index 129eaf5f4..5cbcfb181 100644 --- a/src/main/java/org/scijava/util/ColorRGB.java +++ b/src/main/java/org/scijava/util/ColorRGB.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ColorRGBA.java b/src/main/java/org/scijava/util/ColorRGBA.java index b7c55622b..34f2dac25 100644 --- a/src/main/java/org/scijava/util/ColorRGBA.java +++ b/src/main/java/org/scijava/util/ColorRGBA.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Colors.java b/src/main/java/org/scijava/util/Colors.java index f32b4fad9..fcc65027b 100644 --- a/src/main/java/org/scijava/util/Colors.java +++ b/src/main/java/org/scijava/util/Colors.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/CombineAnnotations.java b/src/main/java/org/scijava/util/CombineAnnotations.java index 002659f4a..b248d64b3 100644 --- a/src/main/java/org/scijava/util/CombineAnnotations.java +++ b/src/main/java/org/scijava/util/CombineAnnotations.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Combiner.java b/src/main/java/org/scijava/util/Combiner.java index e4babbe96..209c57c08 100644 --- a/src/main/java/org/scijava/util/Combiner.java +++ b/src/main/java/org/scijava/util/Combiner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ConversionUtils.java b/src/main/java/org/scijava/util/ConversionUtils.java index 99b30254c..e1dd17570 100644 --- a/src/main/java/org/scijava/util/ConversionUtils.java +++ b/src/main/java/org/scijava/util/ConversionUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,22 +30,66 @@ package org.scijava.util; import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; import org.scijava.convert.ConversionRequest; import org.scijava.convert.ConvertService; import org.scijava.convert.Converter; -import org.scijava.convert.DefaultConverter; -import org.scijava.util.Types; /** @deprecated use {@link ConvertService} and {@link Types} */ @Deprecated public class ConversionUtils { - private static ConvertService convertService; - - private static Converter converterNoContext; - - private static double servicePriority = 0.0; + private static List> converters = Arrays.asList( + new org.scijava.convert.NullConverter(), + new org.scijava.convert.CastingConverter(), + new org.scijava.convert.ArrayConverters.BoolArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.BoolArrayWrapper(), + new org.scijava.convert.ArrayConverters.ByteArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.ByteArrayWrapper(), + new org.scijava.convert.ArrayConverters.CharArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.CharArrayWrapper(), + new org.scijava.convert.ArrayConverters.DoubleArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.DoubleArrayWrapper(), + new org.scijava.convert.ArrayConverters.FloatArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.FloatArrayWrapper(), + new org.scijava.convert.ArrayConverters.IntArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.IntArrayWrapper(), + new org.scijava.convert.ArrayConverters.LongArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.LongArrayWrapper(), + new org.scijava.convert.ArrayConverters.ShortArrayUnwrapper(), + new org.scijava.convert.ArrayConverters.ShortArrayWrapper(), + new org.scijava.convert.FileListConverters.FileArrayToStringConverter(), + new org.scijava.convert.FileListConverters.FileToStringConverter(), + new org.scijava.convert.FileListConverters.StringToFileArrayConverter(), + new org.scijava.convert.FileListConverters.StringToFileConverter(), + new org.scijava.convert.NumberConverters.BigIntegerToBigDecimalConverter(), + new org.scijava.convert.NumberConverters.ByteToBigDecimalConverter(), + new org.scijava.convert.NumberConverters.ByteToBigIntegerConverter(), + new org.scijava.convert.NumberConverters.ByteToDoubleConverter(), + new org.scijava.convert.NumberConverters.ByteToFloatConverter(), + new org.scijava.convert.NumberConverters.ByteToIntegerConverter(), + new org.scijava.convert.NumberConverters.ByteToLongConverter(), + new org.scijava.convert.NumberConverters.ByteToShortConverter(), + new org.scijava.convert.NumberConverters.DoubleToBigDecimalConverter(), + new org.scijava.convert.NumberConverters.FloatToBigDecimalConverter(), + new org.scijava.convert.NumberConverters.FloatToDoubleConverter(), + new org.scijava.convert.NumberConverters.IntegerToBigDecimalConverter(), + new org.scijava.convert.NumberConverters.IntegerToBigIntegerConverter(), + new org.scijava.convert.NumberConverters.IntegerToDoubleConverter(), + new org.scijava.convert.NumberConverters.IntegerToLongConverter(), + new org.scijava.convert.NumberConverters.LongToBigDecimalConverter(), + new org.scijava.convert.NumberConverters.LongToBigIntegerConverter(), + new org.scijava.convert.NumberConverters.ShortToBigDecimalConverter(), + new org.scijava.convert.NumberConverters.ShortToBigIntegerConverter(), + new org.scijava.convert.NumberConverters.ShortToDoubleConverter(), + new org.scijava.convert.NumberConverters.ShortToFloatConverter(), + new org.scijava.convert.NumberConverters.ShortToIntegerConverter(), + new org.scijava.convert.NumberConverters.ShortToLongConverter(), + new org.scijava.convert.StringToNumberConverter(), + new org.scijava.convert.DefaultConverter() + ); private ConversionUtils() { // prevent instantiation of utility class @@ -53,18 +97,13 @@ private ConversionUtils() { // -- ConvertService setter -- - /** - * Sets the {@link ConvertService} to use for handling conversion requests. - */ + /** @deprecated This method should not be used anymore. */ + @Deprecated + @SuppressWarnings("unused") public static void setDelegateService(final ConvertService convertService, final double priority) { - if (ConversionUtils.convertService == null || Double.compare(priority, - servicePriority) > 0) - { - ConversionUtils.convertService = convertService; - servicePriority = priority; - } + // NB: This method is now a no-op. } // -- Deprecated methods -- @@ -209,17 +248,11 @@ public static T getNullValue(final Class type) { // -- Helper methods -- /** - * Gets the {@link Converter} to use for the given conversion request. If the - * delegate {@link ConvertService} has not been explicitly set, then a - * {@link DefaultConverter} will be used. + * Gets the {@link Converter} to use for the given conversion request. * * @return The {@link Converter} to use for handling the given request. */ private static Converter handler(final ConversionRequest data) { - if (convertService != null) return convertService.getHandler(data); - - if (converterNoContext == null) converterNoContext = new DefaultConverter(); - - return converterNoContext; + return converters.stream().filter(c -> c.supports(data)).findFirst().orElse(null); } } diff --git a/src/main/java/org/scijava/util/DebugUtils.java b/src/main/java/org/scijava/util/DebugUtils.java index 4e88f180b..44e28f780 100644 --- a/src/main/java/org/scijava/util/DebugUtils.java +++ b/src/main/java/org/scijava/util/DebugUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/DefaultTreeNode.java b/src/main/java/org/scijava/util/DefaultTreeNode.java index db60c7673..e2c97985d 100644 --- a/src/main/java/org/scijava/util/DefaultTreeNode.java +++ b/src/main/java/org/scijava/util/DefaultTreeNode.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/DigestUtils.java b/src/main/java/org/scijava/util/DigestUtils.java index b78af02ae..84a79eb66 100644 --- a/src/main/java/org/scijava/util/DigestUtils.java +++ b/src/main/java/org/scijava/util/DigestUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,8 +32,7 @@ import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; - -import javax.xml.bind.DatatypeConverter; +import java.util.Base64; /** * Utility class for computing cryptographic hashes. @@ -98,7 +97,7 @@ public static String hex(final byte[] bytes) { /** Converts the given byte array to a base64 string. */ public static String base64(final byte[] bytes) { - return DatatypeConverter.printBase64Binary(bytes); + return new String(Base64.getEncoder().encode(bytes)); } /** diff --git a/src/main/java/org/scijava/util/DoubleArray.java b/src/main/java/org/scijava/util/DoubleArray.java index 928d62af6..de007478c 100644 --- a/src/main/java/org/scijava/util/DoubleArray.java +++ b/src/main/java/org/scijava/util/DoubleArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/FileUtils.java b/src/main/java/org/scijava/util/FileUtils.java index 4de14f37f..2761edf73 100644 --- a/src/main/java/org/scijava/util/FileUtils.java +++ b/src/main/java/org/scijava/util/FileUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,7 +28,7 @@ */ // File path shortening code adapted from: -// from: http://www.rgagnon.com/javadetails/java-0661.html +// from: https://www.rgagnon.com/javadetails/java-0661.html package org.scijava.util; @@ -729,8 +729,9 @@ private static String classifiers() { "sources", "javadoc", "natives?-?\\w*", - "(natives-)?(android|linux|macosx|solaris|windows)-" + - "(aarch64|amd64|arm|armv6|armv6hf|i586|universal|x86|x86_64)", + "(natives-)?(android|linux|macosx|macos|solaris|windows)-" + + "(aarch64|amd64|arm64|armv6hf|armv6|arm|" + + "i386|i486|i586|i686|universal|x86[_-]32|x86[_-]64|x86)", }; final StringBuilder sb = new StringBuilder("("); for (final String classifier : classifiers) { diff --git a/src/main/java/org/scijava/util/FloatArray.java b/src/main/java/org/scijava/util/FloatArray.java index f232814d6..49046497a 100644 --- a/src/main/java/org/scijava/util/FloatArray.java +++ b/src/main/java/org/scijava/util/FloatArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/GenericUtils.java b/src/main/java/org/scijava/util/GenericUtils.java index fd5d3e9a7..9cdb71614 100644 --- a/src/main/java/org/scijava/util/GenericUtils.java +++ b/src/main/java/org/scijava/util/GenericUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/IntArray.java b/src/main/java/org/scijava/util/IntArray.java index 6d0086a17..f3c6a8e71 100644 --- a/src/main/java/org/scijava/util/IntArray.java +++ b/src/main/java/org/scijava/util/IntArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/IntCoords.java b/src/main/java/org/scijava/util/IntCoords.java index 80d18eafc..d0498a7f3 100644 --- a/src/main/java/org/scijava/util/IntCoords.java +++ b/src/main/java/org/scijava/util/IntCoords.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/IntRect.java b/src/main/java/org/scijava/util/IntRect.java index 508fc5eeb..33670744f 100644 --- a/src/main/java/org/scijava/util/IntRect.java +++ b/src/main/java/org/scijava/util/IntRect.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/IteratorPlus.java b/src/main/java/org/scijava/util/IteratorPlus.java index 990246fd9..35c9cd3b6 100644 --- a/src/main/java/org/scijava/util/IteratorPlus.java +++ b/src/main/java/org/scijava/util/IteratorPlus.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/LastRecentlyUsed.java b/src/main/java/org/scijava/util/LastRecentlyUsed.java index 84ea1ecb8..50d292856 100644 --- a/src/main/java/org/scijava/util/LastRecentlyUsed.java +++ b/src/main/java/org/scijava/util/LastRecentlyUsed.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -143,7 +143,7 @@ public boolean replace(final int index, T newValue) { throw new IllegalArgumentException("No current entry at position " + index); } - if (newValue.equals(previous)) return false; + if (newValue.equals(previousValue)) return false; map.remove(previousValue); map.put(newValue, index); entries[index] = newValue; diff --git a/src/main/java/org/scijava/util/LineOutputStream.java b/src/main/java/org/scijava/util/LineOutputStream.java index 38b014a14..b0cd47e87 100644 --- a/src/main/java/org/scijava/util/LineOutputStream.java +++ b/src/main/java/org/scijava/util/LineOutputStream.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ListUtils.java b/src/main/java/org/scijava/util/ListUtils.java index 170124839..8f07d06a3 100644 --- a/src/main/java/org/scijava/util/ListUtils.java +++ b/src/main/java/org/scijava/util/ListUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,7 +28,7 @@ */ // File path shortening code adapted from: -// from: http://www.rgagnon.com/javadetails/java-0661.html +// from: https://www.rgagnon.com/javadetails/java-0661.html package org.scijava.util; diff --git a/src/main/java/org/scijava/util/LongArray.java b/src/main/java/org/scijava/util/LongArray.java index 61ffed4a9..12ae4a737 100644 --- a/src/main/java/org/scijava/util/LongArray.java +++ b/src/main/java/org/scijava/util/LongArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Manifest.java b/src/main/java/org/scijava/util/Manifest.java index 807eaa05f..58100535e 100644 --- a/src/main/java/org/scijava/util/Manifest.java +++ b/src/main/java/org/scijava/util/Manifest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/MersenneTwisterFast.java b/src/main/java/org/scijava/util/MersenneTwisterFast.java index 2abb4d206..e1cdb4a48 100644 --- a/src/main/java/org/scijava/util/MersenneTwisterFast.java +++ b/src/main/java/org/scijava/util/MersenneTwisterFast.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/MetaInfCombiner.java b/src/main/java/org/scijava/util/MetaInfCombiner.java index 745c39195..3d03195f6 100644 --- a/src/main/java/org/scijava/util/MetaInfCombiner.java +++ b/src/main/java/org/scijava/util/MetaInfCombiner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/MirrorWebsite.java b/src/main/java/org/scijava/util/MirrorWebsite.java index d8f076e40..2b5bdf4f9 100644 --- a/src/main/java/org/scijava/util/MirrorWebsite.java +++ b/src/main/java/org/scijava/util/MirrorWebsite.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -58,7 +58,7 @@ * This program mirrors a given website. *

    * Its primary purpose is to provide the code necessary to keep ImageJ Mirror up-to-date. + * href="https://mirror.imagej.net/">ImageJ Mirror up-to-date. *

    * * @author Johannes Schindelin diff --git a/src/main/java/org/scijava/util/MiscUtils.java b/src/main/java/org/scijava/util/MiscUtils.java index 492e2150e..eb9fad0c1 100644 --- a/src/main/java/org/scijava/util/MiscUtils.java +++ b/src/main/java/org/scijava/util/MiscUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/NumberUtils.java b/src/main/java/org/scijava/util/NumberUtils.java index ea9f684ac..ba3fdc6d9 100644 --- a/src/main/java/org/scijava/util/NumberUtils.java +++ b/src/main/java/org/scijava/util/NumberUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -78,6 +78,8 @@ public static Number getMinimumNumber(final Class type) { if (Types.isLong(type)) return Long.MIN_VALUE; if (Types.isFloat(type)) return -Float.MAX_VALUE; if (Types.isDouble(type)) return -Double.MAX_VALUE; + // Fallback for Number.class + if (Types.isNumber(type)) return -Double.MAX_VALUE; return null; } @@ -88,6 +90,8 @@ public static Number getMaximumNumber(final Class type) { if (Types.isLong(type)) return Long.MAX_VALUE; if (Types.isFloat(type)) return Float.MAX_VALUE; if (Types.isDouble(type)) return Double.MAX_VALUE; + // Fallback for Number.class + if (Types.isNumber(type)) return Double.MAX_VALUE; return null; } diff --git a/src/main/java/org/scijava/util/ObjectArray.java b/src/main/java/org/scijava/util/ObjectArray.java index 2564da853..daaa6e7ed 100644 --- a/src/main/java/org/scijava/util/ObjectArray.java +++ b/src/main/java/org/scijava/util/ObjectArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,8 +32,6 @@ import java.util.Arrays; import java.util.Collection; -import org.scijava.util.Types; - /** * An extensible, generic array of {@code Object} elements. Note that this class * is a {@link PrimitiveArray} but of course Objects are not primitives. diff --git a/src/main/java/org/scijava/util/POM.java b/src/main/java/org/scijava/util/POM.java index 8de96e17f..ed7dc8009 100644 --- a/src/main/java/org/scijava/util/POM.java +++ b/src/main/java/org/scijava/util/POM.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -335,7 +335,7 @@ public static List getAllPOMs() { * that one has a suffix beginning with a dash ({@code -}), the version with * suffix will be considered less than the one without a suffix. The * reason for this is to accommodate the SemVer versioning scheme's usage of + * href="https://semver.org/">SemVer versioning scheme's usage of * "prerelease" version suffixes. For example, {@code 2.0.0} will compare * greater than {@code 2.0.0-beta-1}, whereas {@code 2.0.0} will compare less * than {@code 2.0.0.1}.
  • diff --git a/src/main/java/org/scijava/util/PlatformUtils.java b/src/main/java/org/scijava/util/PlatformUtils.java index d1b82104d..a8b8cf909 100644 --- a/src/main/java/org/scijava/util/PlatformUtils.java +++ b/src/main/java/org/scijava/util/PlatformUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Prefs.java b/src/main/java/org/scijava/util/Prefs.java index f946b587f..f70bd70d1 100644 --- a/src/main/java/org/scijava/util/Prefs.java +++ b/src/main/java/org/scijava/util/Prefs.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/PrimitiveArray.java b/src/main/java/org/scijava/util/PrimitiveArray.java index 8e72eb8ec..6efb5e463 100644 --- a/src/main/java/org/scijava/util/PrimitiveArray.java +++ b/src/main/java/org/scijava/util/PrimitiveArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ProcessUtils.java b/src/main/java/org/scijava/util/ProcessUtils.java index 698b1ae78..2e5cb62e5 100644 --- a/src/main/java/org/scijava/util/ProcessUtils.java +++ b/src/main/java/org/scijava/util/ProcessUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/PropertiesHelper.java b/src/main/java/org/scijava/util/PropertiesHelper.java new file mode 100644 index 000000000..c2abeb78b --- /dev/null +++ b/src/main/java/org/scijava/util/PropertiesHelper.java @@ -0,0 +1,72 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.util; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +/** + * Simple utility for reading and writing a property map to/from plain text. + */ +public final class PropertiesHelper { + + public static Map get(File filename) { + Map map = new HashMap<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.split("=", 2); + if (parts.length == 2) { + map.put(parts[0], parts[1]); + } + } + } + catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + catch (IOException e) { + throw new RuntimeException(e); + } + return map; + } + + public static void put(Map properties, File filename) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) { + for (Map.Entry entry : properties.entrySet()) { + writer.write(entry.getKey() + "=" + entry.getValue()); + writer.newLine(); + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/org/scijava/util/Query.java b/src/main/java/org/scijava/util/Query.java index 2973c004e..7217b290e 100644 --- a/src/main/java/org/scijava/util/Query.java +++ b/src/main/java/org/scijava/util/Query.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ReadInto.java b/src/main/java/org/scijava/util/ReadInto.java index 5e822926b..cefca34fd 100644 --- a/src/main/java/org/scijava/util/ReadInto.java +++ b/src/main/java/org/scijava/util/ReadInto.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/RealCoords.java b/src/main/java/org/scijava/util/RealCoords.java index d55f0cdfe..fd949dbbf 100644 --- a/src/main/java/org/scijava/util/RealCoords.java +++ b/src/main/java/org/scijava/util/RealCoords.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/RealRect.java b/src/main/java/org/scijava/util/RealRect.java index c58fbb7a8..507406235 100644 --- a/src/main/java/org/scijava/util/RealRect.java +++ b/src/main/java/org/scijava/util/RealRect.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ReflectException.java b/src/main/java/org/scijava/util/ReflectException.java index 2096b73cf..bc4e0f246 100644 --- a/src/main/java/org/scijava/util/ReflectException.java +++ b/src/main/java/org/scijava/util/ReflectException.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ReflectedUniverse.java b/src/main/java/org/scijava/util/ReflectedUniverse.java index 53c0e0ab7..c43a05dab 100644 --- a/src/main/java/org/scijava/util/ReflectedUniverse.java +++ b/src/main/java/org/scijava/util/ReflectedUniverse.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/ServiceCombiner.java b/src/main/java/org/scijava/util/ServiceCombiner.java index 65bf24190..64053aa7c 100644 --- a/src/main/java/org/scijava/util/ServiceCombiner.java +++ b/src/main/java/org/scijava/util/ServiceCombiner.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,12 +40,10 @@ import java.util.Map; import java.util.Map.Entry; -import javax.xml.ws.Service; - import org.scijava.Context; /** - * Combines {@link Service} information from all JAR files on the classpath. + * Combines {@code Service} information from all JAR files on the classpath. * * @author Johannes Schindelin * @author Mark Hiner diff --git a/src/main/java/org/scijava/util/ShortArray.java b/src/main/java/org/scijava/util/ShortArray.java index 50ca80a10..935bf6b96 100644 --- a/src/main/java/org/scijava/util/ShortArray.java +++ b/src/main/java/org/scijava/util/ShortArray.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Sizable.java b/src/main/java/org/scijava/util/Sizable.java index b4939d7c8..21a1466d7 100644 --- a/src/main/java/org/scijava/util/Sizable.java +++ b/src/main/java/org/scijava/util/Sizable.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/SizableArrayList.java b/src/main/java/org/scijava/util/SizableArrayList.java index 163ae5939..889135a44 100644 --- a/src/main/java/org/scijava/util/SizableArrayList.java +++ b/src/main/java/org/scijava/util/SizableArrayList.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/StringMaker.java b/src/main/java/org/scijava/util/StringMaker.java index 97af599da..3df9b8786 100644 --- a/src/main/java/org/scijava/util/StringMaker.java +++ b/src/main/java/org/scijava/util/StringMaker.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/StringUtils.java b/src/main/java/org/scijava/util/StringUtils.java index 6516777b2..a38afb144 100644 --- a/src/main/java/org/scijava/util/StringUtils.java +++ b/src/main/java/org/scijava/util/StringUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Timing.java b/src/main/java/org/scijava/util/Timing.java index d533840f6..9cd4a1863 100644 --- a/src/main/java/org/scijava/util/Timing.java +++ b/src/main/java/org/scijava/util/Timing.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/TreeNode.java b/src/main/java/org/scijava/util/TreeNode.java index a0ed8a293..f302f9e59 100644 --- a/src/main/java/org/scijava/util/TreeNode.java +++ b/src/main/java/org/scijava/util/TreeNode.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/TunePlayer.java b/src/main/java/org/scijava/util/TunePlayer.java index a59e2019b..8ade8a695 100644 --- a/src/main/java/org/scijava/util/TunePlayer.java +++ b/src/main/java/org/scijava/util/TunePlayer.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/Types.java b/src/main/java/org/scijava/util/Types.java index 441516eaa..f9c9068a9 100644 --- a/src/main/java/org/scijava/util/Types.java +++ b/src/main/java/org/scijava/util/Types.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -780,8 +780,10 @@ public static T cast(final Object src, final Class dest) { } /** - * Converts the given string value to an enumeration constant of the specified - * type. + * Converts the given string value to an enumeration constant of the + * specified type. For example, {@code enumValue("APPLE", Fruit.class)} + * returns {@code Fruit.APPLE} if such a value is among those of the + * requested enum class. * * @param name The value to convert. * @param dest The type of the enumeration constant. @@ -798,6 +800,60 @@ public static T enumValue(final String name, final Class dest) { return typedResult; } + /** + * Converts the given string label to an enumeration constant of the + * specified type. An enum label is the string returned by the enum constant's + * {@link Object#toString()} method. For example, + * {@code enumFromLabel("Apple", Fruit.class)} returns {@code Fruit.APPLE} if + * {@code Fruit.APPLE.toString()} is implemented to return {@code "Apple"}. + * + * @param label The {@code toString()} result of the desired enum value. + * @param dest The type of the enumeration constant. + * @return The matching enumeration constant. + * @throws IllegalArgumentException if the type is not an enumeration type, or + * has no constant with the given label. + */ + public static T enumFromLabel(final String label, final Class dest) { + final T[] values = dest.getEnumConstants(); + if (values == null) throw iae("Not an enum type: " + name(dest)); + for (T value : values) { + if (Objects.equals(label, value.toString())) return value; + } + throw iae("Enum class " + dest.getName() + " has no such label: " + label); + } + + /** + * Converts the given string value or label to an enumeration constant of the + * specified type. + *

    + * If the string matches one of the enum values directly, that value will be + * returned via {@link #enumValue(String, Class)}. Otherwise, the result of + * {@link #enumFromLabel} is returned. + *

    + * + * @param s The name or label of the desired enum value. + * @param dest The type of the enumeration constant. + * @return The matching enumeration constant. + * @throws IllegalArgumentException if the type is not an enumeration type, + * or has no such constant with the given name nor label. + */ + public static T enumFromString(final String s, final Class dest) { + if (!dest.isEnum()) throw iae("Not an enum type: " + name(dest)); + try { + return enumValue(s, dest); + } + catch (final IllegalArgumentException exc) { + // NB: No action needed. + } + try { + return enumFromLabel(s, dest); + } + catch (final IllegalArgumentException exc) { + // NB: No action needed. + } + throw iae("Enum class " + dest.getName() + " has no such value nor label: " + s); + } + /** * Creates a new {@link ParameterizedType} of the given class together with * the specified type arguments. @@ -998,7 +1054,7 @@ private static Class arrayOrNull(final Class componentType) { * (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 + * https://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, @@ -3485,8 +3541,6 @@ else if (type instanceof GenericArrayType) { } private static Type[] getArrayExactDirectSuperTypes(final Type arrayType) { - // see - // http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.3 final Type typeComponent = getArrayComponentType(arrayType); Type[] result; diff --git a/src/main/java/org/scijava/util/UnitUtils.java b/src/main/java/org/scijava/util/UnitUtils.java index 1d45f7aac..43c13f1cb 100644 --- a/src/main/java/org/scijava/util/UnitUtils.java +++ b/src/main/java/org/scijava/util/UnitUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/VersionUtils.java b/src/main/java/org/scijava/util/VersionUtils.java index 994a4aa71..2d7e97a32 100644 --- a/src/main/java/org/scijava/util/VersionUtils.java +++ b/src/main/java/org/scijava/util/VersionUtils.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/util/XML.java b/src/main/java/org/scijava/util/XML.java index e1b570d37..0dcbb1126 100644 --- a/src/main/java/org/scijava/util/XML.java +++ b/src/main/java/org/scijava/util/XML.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/welcome/DefaultWelcomeService.java b/src/main/java/org/scijava/welcome/DefaultWelcomeService.java index 186b28260..8977b0001 100644 --- a/src/main/java/org/scijava/welcome/DefaultWelcomeService.java +++ b/src/main/java/org/scijava/welcome/DefaultWelcomeService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/welcome/WelcomeService.java b/src/main/java/org/scijava/welcome/WelcomeService.java index c7a1ec948..8e2f77aec 100644 --- a/src/main/java/org/scijava/welcome/WelcomeService.java +++ b/src/main/java/org/scijava/welcome/WelcomeService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/welcome/event/WelcomeEvent.java b/src/main/java/org/scijava/welcome/event/WelcomeEvent.java index 8ea1f3424..6f9c5946c 100644 --- a/src/main/java/org/scijava/welcome/event/WelcomeEvent.java +++ b/src/main/java/org/scijava/welcome/event/WelcomeEvent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/AbstractInputHarvester.java b/src/main/java/org/scijava/widget/AbstractInputHarvester.java index 1f65ae1d5..0785fa157 100644 --- a/src/main/java/org/scijava/widget/AbstractInputHarvester.java +++ b/src/main/java/org/scijava/widget/AbstractInputHarvester.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,9 +30,11 @@ package org.scijava.widget; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.scijava.AbstractContextual; import org.scijava.convert.ConvertService; @@ -119,8 +121,15 @@ private WidgetModel addInput(final InputPanel inputPanel, } if (item.isRequired()) { - throw new ModuleException("A " + type.getSimpleName() + - " is required but none exist."); + final List vowelSoundPrefixes = Arrays.asList( + "a", "e", "i", "o", "u", "honor", "honour", "hour", "xml" + ); + final String typeName = type.getSimpleName(); + final String article = vowelSoundPrefixes.stream().anyMatch( + prefix -> typeName.toLowerCase().startsWith(prefix) + ) ? "An" : "A"; + throw new ModuleException(article + " " + typeName + + " is required but none is available."); } // item is not required; we can skip it @@ -128,13 +137,25 @@ private WidgetModel addInput(final InputPanel inputPanel, } /** Asks the object service and convert service for valid choices */ - @SuppressWarnings("unchecked") - private List getObjects(final Class type) { - @SuppressWarnings("rawtypes") - Set compatibleInputs = - new HashSet(convertService.getCompatibleInputs(type)); - compatibleInputs.addAll(objectService.getObjects(type)); - return new ArrayList<>(compatibleInputs); + private List getObjects(final Class type) { + // Start with the known, unconverted objects of the desired type + List objects = new ArrayList<>(objectService.getObjects(type)); + + // Get all the known objects that can be converted to the destination type + Collection compatibleInputs = convertService.getCompatibleInputs(type); + + // HACK: Add each convertible object that doesn't share a name with any other object + // Our goal here is to de-duplicate by avoiding similar inputs that could be converted + // to the same effective output (e.g. an ImageDisplay and a Dataset that map to the same + // ImgPlus) + Set knownNames = objects.stream().map(Object::toString).collect(Collectors.toSet()); + for (Object o : compatibleInputs) { + final String s = o.toString(); + if (!knownNames.contains(s)) { + objects.add(o); + knownNames.add(s); + } + } + return objects; } - } diff --git a/src/main/java/org/scijava/widget/AbstractInputPanel.java b/src/main/java/org/scijava/widget/AbstractInputPanel.java index 2a8bb49a5..756f5ed15 100644 --- a/src/main/java/org/scijava/widget/AbstractInputPanel.java +++ b/src/main/java/org/scijava/widget/AbstractInputPanel.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/AbstractInputWidget.java b/src/main/java/org/scijava/widget/AbstractInputWidget.java index f527847b0..b6304cfd3 100644 --- a/src/main/java/org/scijava/widget/AbstractInputWidget.java +++ b/src/main/java/org/scijava/widget/AbstractInputWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/Button.java b/src/main/java/org/scijava/widget/Button.java index 286cd1fb4..3ddfa0217 100644 --- a/src/main/java/org/scijava/widget/Button.java +++ b/src/main/java/org/scijava/widget/Button.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/ButtonWidget.java b/src/main/java/org/scijava/widget/ButtonWidget.java index c869fc13e..c836c522d 100644 --- a/src/main/java/org/scijava/widget/ButtonWidget.java +++ b/src/main/java/org/scijava/widget/ButtonWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/ChoiceWidget.java b/src/main/java/org/scijava/widget/ChoiceWidget.java index b900ac0ba..275b39607 100644 --- a/src/main/java/org/scijava/widget/ChoiceWidget.java +++ b/src/main/java/org/scijava/widget/ChoiceWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/ColorWidget.java b/src/main/java/org/scijava/widget/ColorWidget.java index 84284a9dd..93573a5ca 100644 --- a/src/main/java/org/scijava/widget/ColorWidget.java +++ b/src/main/java/org/scijava/widget/ColorWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/DateWidget.java b/src/main/java/org/scijava/widget/DateWidget.java index d05049bf7..ecd9953cb 100644 --- a/src/main/java/org/scijava/widget/DateWidget.java +++ b/src/main/java/org/scijava/widget/DateWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/DefaultWidgetModel.java b/src/main/java/org/scijava/widget/DefaultWidgetModel.java index 229195289..e7d6b9352 100644 --- a/src/main/java/org/scijava/widget/DefaultWidgetModel.java +++ b/src/main/java/org/scijava/widget/DefaultWidgetModel.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,7 +29,6 @@ package org.scijava.widget; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; @@ -80,6 +79,8 @@ public class DefaultWidgetModel extends AbstractContextual implements WidgetMode private boolean initialized; + private String validationMessage; + public DefaultWidgetModel(final Context context, final InputPanel inputPanel, final Module module, final ModuleItem item, final List objectPool) { @@ -156,6 +157,7 @@ public void setValue(final Object value) { // Pass the value through the convertService convertedInput = convertService.convert(value, item.getType()); + if (convertedInput == null) convertedInput = value; // If we get a different (converted) value back, cache it weakly. if (convertedInput != value) { @@ -167,6 +169,11 @@ public void setValue(final Object value) { if (initialized) { threadService.queue(() -> { callback(); + // Revalidate all inputs: changing one value may affect others' validity. + for (final ModuleItem anyItem : module.getInfo().inputs()) { + final InputWidget w = inputPanel.getWidget(anyItem.getName()); + if (w != null) w.get().updateValidation(); + } inputPanel.refresh(); // must be on AWT thread? module.preview(); }); @@ -220,7 +227,7 @@ public Number getStepSize() { @Override public String[] getChoices() { - final List choicesList = item.getChoices(); + final List choicesList = getItem().getChoices(); if (choicesList == null) return null; final String[] choices = new String[choicesList.size()]; for (int i = 0; i < choices.length; i++) { @@ -284,16 +291,25 @@ public boolean isInitialized() { return initialized; } + @Override + public String getValidationMessage() { + return validationMessage; + } + + @Override + public void updateValidation() { + validationMessage = item.validateMessage(module); + } + // -- Helper methods -- /** * For multiple choice widgets, ensures the value is a valid choice. * - * @see #getChoices() * @see ChoiceWidget */ private Object ensureValidChoice(final Object value) { - return ensureValid(value, Arrays.asList(getChoices())); + return ensureValid(value, getItem().getChoices()); } /** diff --git a/src/main/java/org/scijava/widget/DefaultWidgetService.java b/src/main/java/org/scijava/widget/DefaultWidgetService.java index 2606eed13..7ceaf2c45 100644 --- a/src/main/java/org/scijava/widget/DefaultWidgetService.java +++ b/src/main/java/org/scijava/widget/DefaultWidgetService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/FileListWidget.java b/src/main/java/org/scijava/widget/FileListWidget.java index d74ea12f5..466f51d2f 100644 --- a/src/main/java/org/scijava/widget/FileListWidget.java +++ b/src/main/java/org/scijava/widget/FileListWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/FileWidget.java b/src/main/java/org/scijava/widget/FileWidget.java index dc70e0ce1..dcf38039d 100644 --- a/src/main/java/org/scijava/widget/FileWidget.java +++ b/src/main/java/org/scijava/widget/FileWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -59,4 +59,11 @@ public interface FileWidget extends InputWidget { */ String DIRECTORY_STYLE = "directory"; + /** + * Widget style for directory chooser dialogs. + * + * @see org.scijava.plugin.Parameter#style() + */ + String FILE_AND_DIRECTORY_STYLE = "both"; + } diff --git a/src/main/java/org/scijava/widget/InputHarvester.java b/src/main/java/org/scijava/widget/InputHarvester.java index 08b1a9fe3..c0638cd96 100644 --- a/src/main/java/org/scijava/widget/InputHarvester.java +++ b/src/main/java/org/scijava/widget/InputHarvester.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/InputPanel.java b/src/main/java/org/scijava/widget/InputPanel.java index 0813ee375..27869b777 100644 --- a/src/main/java/org/scijava/widget/InputPanel.java +++ b/src/main/java/org/scijava/widget/InputPanel.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/InputWidget.java b/src/main/java/org/scijava/widget/InputWidget.java index 43d931c01..fe12174a0 100644 --- a/src/main/java/org/scijava/widget/InputWidget.java +++ b/src/main/java/org/scijava/widget/InputWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/MessageWidget.java b/src/main/java/org/scijava/widget/MessageWidget.java index 4092544eb..fe4877975 100644 --- a/src/main/java/org/scijava/widget/MessageWidget.java +++ b/src/main/java/org/scijava/widget/MessageWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/NumberWidget.java b/src/main/java/org/scijava/widget/NumberWidget.java index 886d423ea..f0aaefe28 100644 --- a/src/main/java/org/scijava/widget/NumberWidget.java +++ b/src/main/java/org/scijava/widget/NumberWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/ObjectWidget.java b/src/main/java/org/scijava/widget/ObjectWidget.java index 2870ff270..925826ab9 100644 --- a/src/main/java/org/scijava/widget/ObjectWidget.java +++ b/src/main/java/org/scijava/widget/ObjectWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/TextWidget.java b/src/main/java/org/scijava/widget/TextWidget.java index 384523125..401d22076 100644 --- a/src/main/java/org/scijava/widget/TextWidget.java +++ b/src/main/java/org/scijava/widget/TextWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/ToggleWidget.java b/src/main/java/org/scijava/widget/ToggleWidget.java index bdb87913a..11c028862 100644 --- a/src/main/java/org/scijava/widget/ToggleWidget.java +++ b/src/main/java/org/scijava/widget/ToggleWidget.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/UIComponent.java b/src/main/java/org/scijava/widget/UIComponent.java index 54e38acb9..e36fcd919 100644 --- a/src/main/java/org/scijava/widget/UIComponent.java +++ b/src/main/java/org/scijava/widget/UIComponent.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/WidgetModel.java b/src/main/java/org/scijava/widget/WidgetModel.java index 83e8a2f9f..4eb8e2703 100644 --- a/src/main/java/org/scijava/widget/WidgetModel.java +++ b/src/main/java/org/scijava/widget/WidgetModel.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -187,6 +187,27 @@ public interface WidgetModel extends Contextual { /** Gets whether the input is compatible with the given type. */ boolean isType(Class type); + /** + * Gets the current validation error message for this widget. + * + * @return the error message from the most recent validation run, or + * {@code null} if the last validation passed or no validation has + * been run yet. + * @see org.scijava.module.ModuleItem#validateMessage(org.scijava.module.Module) + */ + String getValidationMessage(); + + /** + * Re-runs this item's validation and updates the stored validation message. + *

    + * This should be called on all widgets whenever any parameter value changes, + * since a change to one parameter may affect the validity of others. + *

    + * + * @see #getValidationMessage() + */ + void updateValidation(); + /** * Toggles the widget's initialization state. An initialized widget can be * assumed to be an active part of a container {@link InputPanel}. diff --git a/src/main/java/org/scijava/widget/WidgetService.java b/src/main/java/org/scijava/widget/WidgetService.java index ef74c794a..88bb00e93 100644 --- a/src/main/java/org/scijava/widget/WidgetService.java +++ b/src/main/java/org/scijava/widget/WidgetService.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/org/scijava/widget/WidgetStyle.java b/src/main/java/org/scijava/widget/WidgetStyle.java index ec5e1c466..ddd56824d 100644 --- a/src/main/java/org/scijava/widget/WidgetStyle.java +++ b/src/main/java/org/scijava/widget/WidgetStyle.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/ContextCreationTest.java b/src/test/java/org/scijava/ContextCreationTest.java index b00b19dfb..4760fa340 100644 --- a/src/test/java/org/scijava/ContextCreationTest.java +++ b/src/test/java/org/scijava/ContextCreationTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,6 +42,8 @@ import java.util.List; import org.junit.Test; +import org.scijava.event.ContextCreatedEvent; +import org.scijava.event.EventHandler; import org.scijava.plugin.Parameter; import org.scijava.plugin.PluginIndex; import org.scijava.plugin.PluginInfo; @@ -149,6 +151,14 @@ public void testSciJavaServices() { } } + /** Tests that {@link ContextCreatedEvent} is published as expected. */ + @Test + public void testContextCreatedEvent() { + assertEquals(0, ServiceNoticingContextCreated.created); + final Context context = new Context(ServiceNoticingContextCreated.class); + assertEquals(1, ServiceNoticingContextCreated.created); + } + /** * Tests that dependent {@link Service}s are automatically created and * populated in downstream {@link Service} classes. @@ -441,6 +451,18 @@ private PluginIndex pluginIndex(final Class... plugins) { // -- Helper classes -- + /** A service that notices when {@link ContextCreatedEvent} is published. */ + public static class ServiceNoticingContextCreated extends AbstractService { + + public static int created = 0; + + @EventHandler + public void onEvent(final ContextCreatedEvent evt) { + created++; + } + + } + /** A service which requires a {@link BarService}. */ public static class FooService extends AbstractService { diff --git a/src/test/java/org/scijava/ContextDisposalTest.java b/src/test/java/org/scijava/ContextDisposalTest.java new file mode 100644 index 000000000..50f4a1369 --- /dev/null +++ b/src/test/java/org/scijava/ContextDisposalTest.java @@ -0,0 +1,51 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava; + +import org.junit.Test; + +/** + * Tests disposal of {@link Context}s. + * + * @author Curtis Rueden + */ +public class ContextDisposalTest { + + /** + * Tests that a {@link Context} can be disposed more than once without + * throwing an exception. + */ + @Test + public void testDoubleDisposal() { + final Context context = new Context(); + context.dispose(); + context.dispose(); + } +} diff --git a/src/test/java/org/scijava/ContextInjectionTest.java b/src/test/java/org/scijava/ContextInjectionTest.java index b5b958a4e..7393056fc 100644 --- a/src/test/java/org/scijava/ContextInjectionTest.java +++ b/src/test/java/org/scijava/ContextInjectionTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/SciJavaTest.java b/src/test/java/org/scijava/SciJavaTest.java index 7e1f2866a..2a34e6607 100644 --- a/src/test/java/org/scijava/SciJavaTest.java +++ b/src/test/java/org/scijava/SciJavaTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/AnnotatedA.java b/src/test/java/org/scijava/annotations/AnnotatedA.java index 1226a7e2b..6bf9c3864 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedA.java +++ b/src/test/java/org/scijava/annotations/AnnotatedA.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/AnnotatedB.java b/src/test/java/org/scijava/annotations/AnnotatedB.java index 7993d867a..d723d0e76 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedB.java +++ b/src/test/java/org/scijava/annotations/AnnotatedB.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/AnnotatedC.java b/src/test/java/org/scijava/annotations/AnnotatedC.java index 5e50040a2..a5e4977b4 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedC.java +++ b/src/test/java/org/scijava/annotations/AnnotatedC.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/AnnotatedD.java b/src/test/java/org/scijava/annotations/AnnotatedD.java index 7049ea841..d1a42b98e 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedD.java +++ b/src/test/java/org/scijava/annotations/AnnotatedD.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/AnnotatedInnerClass.java b/src/test/java/org/scijava/annotations/AnnotatedInnerClass.java index 41e9a3849..9f2304ff5 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedInnerClass.java +++ b/src/test/java/org/scijava/annotations/AnnotatedInnerClass.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/Complex.java b/src/test/java/org/scijava/annotations/Complex.java index 4d3b2ae4a..554afabee 100644 --- a/src/test/java/org/scijava/annotations/Complex.java +++ b/src/test/java/org/scijava/annotations/Complex.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/DirectoryIndexerTest.java b/src/test/java/org/scijava/annotations/DirectoryIndexerTest.java index 894dc5aa7..0046a6c7a 100644 --- a/src/test/java/org/scijava/annotations/DirectoryIndexerTest.java +++ b/src/test/java/org/scijava/annotations/DirectoryIndexerTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/EclipseHelperTest.java b/src/test/java/org/scijava/annotations/EclipseHelperTest.java index cffbc9228..9acf9e1d9 100644 --- a/src/test/java/org/scijava/annotations/EclipseHelperTest.java +++ b/src/test/java/org/scijava/annotations/EclipseHelperTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/Fruit.java b/src/test/java/org/scijava/annotations/Fruit.java index 28f04a12c..59fd00b47 100644 --- a/src/test/java/org/scijava/annotations/Fruit.java +++ b/src/test/java/org/scijava/annotations/Fruit.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/LegacyTest.java b/src/test/java/org/scijava/annotations/LegacyTest.java index c12e8930c..4734a4763 100644 --- a/src/test/java/org/scijava/annotations/LegacyTest.java +++ b/src/test/java/org/scijava/annotations/LegacyTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/annotations/Simple.java b/src/test/java/org/scijava/annotations/Simple.java index 2a0b751e3..87a63ddf7 100644 --- a/src/test/java/org/scijava/annotations/Simple.java +++ b/src/test/java/org/scijava/annotations/Simple.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/app/StatusServiceTest.java b/src/test/java/org/scijava/app/StatusServiceTest.java index 5dde120ff..dbca89909 100644 --- a/src/test/java/org/scijava/app/StatusServiceTest.java +++ b/src/test/java/org/scijava/app/StatusServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/command/CommandArrayConverterTest.java b/src/test/java/org/scijava/command/CommandArrayConverterTest.java index 26dfebfc9..7a9915a47 100644 --- a/src/test/java/org/scijava/command/CommandArrayConverterTest.java +++ b/src/test/java/org/scijava/command/CommandArrayConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/command/CommandInfoTest.java b/src/test/java/org/scijava/command/CommandInfoTest.java index d7830f59e..0811f0f44 100644 --- a/src/test/java/org/scijava/command/CommandInfoTest.java +++ b/src/test/java/org/scijava/command/CommandInfoTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/command/CommandModuleTest.java b/src/test/java/org/scijava/command/CommandModuleTest.java index 372ca5267..50080055d 100644 --- a/src/test/java/org/scijava/command/CommandModuleTest.java +++ b/src/test/java/org/scijava/command/CommandModuleTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/command/CommandServiceTest.java b/src/test/java/org/scijava/command/CommandServiceTest.java index a66fe78e3..9465b37ff 100644 --- a/src/test/java/org/scijava/command/CommandServiceTest.java +++ b/src/test/java/org/scijava/command/CommandServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/command/InputsTest.java b/src/test/java/org/scijava/command/InputsTest.java index a5387d6b9..9ca5e46b2 100644 --- a/src/test/java/org/scijava/command/InputsTest.java +++ b/src/test/java/org/scijava/command/InputsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/command/InvalidCommandTest.java b/src/test/java/org/scijava/command/InvalidCommandTest.java index 3d5e11649..84a60851d 100644 --- a/src/test/java/org/scijava/command/InvalidCommandTest.java +++ b/src/test/java/org/scijava/command/InvalidCommandTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/command/run/CommandCodeRunnerTest.java b/src/test/java/org/scijava/command/run/CommandCodeRunnerTest.java index afde6646f..d45954aa7 100644 --- a/src/test/java/org/scijava/command/run/CommandCodeRunnerTest.java +++ b/src/test/java/org/scijava/command/run/CommandCodeRunnerTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/console/ConsoleServiceTest.java b/src/test/java/org/scijava/console/ConsoleServiceTest.java index 9bdb66ba4..f7e36062a 100644 --- a/src/test/java/org/scijava/console/ConsoleServiceTest.java +++ b/src/test/java/org/scijava/console/ConsoleServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -83,9 +83,12 @@ public void testProcessArgs() { */ @Test public void testInfiniteLoopAvoidance() { - assertFalse(consoleService.getInstance(BrokenArgument.class).argsHandled); + final BrokenArgument broken = // + consoleService.getInstance(BrokenArgument.class); + assertNotNull(broken); + assertFalse(broken.argsHandled); consoleService.processArgs("--broken"); - assertTrue(consoleService.getInstance(BrokenArgument.class).argsHandled); + assertTrue(broken.argsHandled); } /** diff --git a/src/test/java/org/scijava/console/SystemPropertyArgumentTest.java b/src/test/java/org/scijava/console/SystemPropertyArgumentTest.java index 830ad7047..63aae7e48 100644 --- a/src/test/java/org/scijava/console/SystemPropertyArgumentTest.java +++ b/src/test/java/org/scijava/console/SystemPropertyArgumentTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/AbstractNumberConverterTests.java b/src/test/java/org/scijava/convert/AbstractNumberConverterTests.java index 1ab9f17d4..d6427e3fc 100644 --- a/src/test/java/org/scijava/convert/AbstractNumberConverterTests.java +++ b/src/test/java/org/scijava/convert/AbstractNumberConverterTests.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ArrayToStringConverterTest.java b/src/test/java/org/scijava/convert/ArrayToStringConverterTest.java new file mode 100644 index 000000000..7393d0261 --- /dev/null +++ b/src/test/java/org/scijava/convert/ArrayToStringConverterTest.java @@ -0,0 +1,177 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.convert; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.parse.ParseService; + +/** + * Tests {@link ArrayToStringConverter}. + * + * @author Gabriel Selzer + */ +public class ArrayToStringConverterTest { + + private final ArrayToStringConverter converter = new ArrayToStringConverter(); + private Context context; + + @Before + public void setUp() { + context = new Context(ConvertService.class, ParseService.class); + context.inject(converter); + } + + @After + public void tearDown() { + context.dispose(); + } + + /** + * Tests the ability of {@link StringToArrayConverter} in converting to arrays + * of various types + */ + @Test + public void testArrayConversion() { + // Component types for array conversions + List arrays = Arrays.asList( // + new byte[] { 1, 2, 3 }, // + new Byte[] { 1, 2, 3 }, // + new short[] { 1, 2, 3 }, // + new Short[] { 1, 2, 3 }, // + new int[] { 1, 2, 3 }, // + new Integer[] { 1, 2, 3 }, // + new long[] { 1, 2, 3 }, // + new Long[] { 1L, 2L, 3L }, // + new float[] { 1, 2, 3 }, // + new Float[] { 1F, 2F, 3F }, // + new double[] { 1, 2, 3 }, // + new Double[] { 1., 2., 3. } // + ); + // String expectation + String sInt = "{1, 2, 3}"; + String sFloat = "{1.0, 2.0, 3.0}"; + for (Object array : arrays) { + // Ensure our Converter can do the conversion + assertTrue(converter.canConvert(array, String.class)); + // Do the conversion + String converted = converter.convert(array, String.class); + // Ensure correctness + assertTrue(converted.equals(sInt) || converted.equals(sFloat)); + } + } + + /** + * Tests the ability of {@link ArrayToStringConverter} in converting + * 2-dimensional arrays + */ + @Test + public void test2DArrayConversion() { + byte[][] arr = new byte[][] { new byte[] { 0, 1 }, new byte[] { 2, 3 } }; + assertTrue(converter.canConvert(arr, String.class)); + String actual = converter.convert(arr, String.class); + String expected = "{{0, 1}, {2, 3}}"; + assertEquals(expected, actual); + } + + /** + * Tests the ability of {@link ArrayToStringConverter} in converting + * 3-dimensional arrays + */ + @Test + public void test3DArrayConversion() { + byte[][][] arr = new byte[2][2][2]; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + for (int k = 0; k < 2; k++) + arr[i][j][k] = (byte) (i + j + k); + + assertTrue(converter.canConvert(arr, String.class)); + String actual = converter.convert(arr, String.class); + String expected = "{{{0, 1}, {1, 2}}, {{1, 2}, {2, 3}}}"; + assertEquals(expected, actual); + } + + /** + * Tests the ability of {@link ArrayToStringConverter} in converting empty + * arrays + */ + @Test + public void testEmptyArrayConversion() { + byte[] arr = new byte[0]; + assertTrue(converter.canConvert(arr, String.class)); + String actual = converter.convert(arr, String.class); + String expected = "{}"; + assertEquals(expected, actual); + } + + /** + * Tests the ability of {@link ArrayToStringConverter} and + * {@link StringToArrayConverter} to perform a cyclic conversion. + */ + @Test + public void testCyclicConversion() { + byte[] expected = new byte[] {1, 2, 3}; + // Do the first conversion + ArrayToStringConverter c1 = new ArrayToStringConverter(); + context.inject(c1); + String converted = c1.convert(expected, String.class); + // Convert back + StringToArrayConverter c2 = new StringToArrayConverter(); + context.inject(c2); + byte[] actual = c2.convert(converted, byte[].class); + assertArrayEquals(expected, actual); + } + + @Test + public void testNullConversion() { + // Do the first conversion + ArrayToStringConverter c1 = new ArrayToStringConverter(); + context.inject(c1); + String converted = c1.convert(new String[] {null}, String.class); + // Try to convert back + StringToArrayConverter c2 = new StringToArrayConverter(); + context.inject(c2); + String[] actual = c2.convert(converted, String[].class); + assertNotNull(actual); + assertEquals(1, actual.length); + assertEquals("null", actual[0]); + } +} diff --git a/src/test/java/org/scijava/convert/BigIntegerToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/BigIntegerToBigDecimalConverterTest.java index a345e9cbd..9b166ee23 100644 --- a/src/test/java/org/scijava/convert/BigIntegerToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/BigIntegerToBigDecimalConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ByteToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/ByteToBigDecimalConverterTest.java index 28ea79d65..50e44776d 100644 --- a/src/test/java/org/scijava/convert/ByteToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToBigDecimalConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ByteToBigIntegerConverterTest.java b/src/test/java/org/scijava/convert/ByteToBigIntegerConverterTest.java index fed7c84ce..11ac2238b 100644 --- a/src/test/java/org/scijava/convert/ByteToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToBigIntegerConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ByteToDoubleConverterTest.java b/src/test/java/org/scijava/convert/ByteToDoubleConverterTest.java index 3b33abecb..f871cfeff 100644 --- a/src/test/java/org/scijava/convert/ByteToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToDoubleConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ByteToFloatConverterTest.java b/src/test/java/org/scijava/convert/ByteToFloatConverterTest.java index 4395c5789..ff08de5b4 100644 --- a/src/test/java/org/scijava/convert/ByteToFloatConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToFloatConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ByteToIntegerConverterTest.java b/src/test/java/org/scijava/convert/ByteToIntegerConverterTest.java index 61724ec62..c19a70311 100644 --- a/src/test/java/org/scijava/convert/ByteToIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToIntegerConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ByteToLongConverterTest.java b/src/test/java/org/scijava/convert/ByteToLongConverterTest.java index 00866555b..58a68e7bc 100644 --- a/src/test/java/org/scijava/convert/ByteToLongConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToLongConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ByteToShortConverterTest.java b/src/test/java/org/scijava/convert/ByteToShortConverterTest.java index 2c307dcce..598e9857f 100644 --- a/src/test/java/org/scijava/convert/ByteToShortConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToShortConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ConvertServiceTest.java b/src/test/java/org/scijava/convert/ConvertServiceTest.java index cca1b2acc..ddb50acab 100644 --- a/src/test/java/org/scijava/convert/ConvertServiceTest.java +++ b/src/test/java/org/scijava/convert/ConvertServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,12 +35,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import java.lang.reflect.Field; import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -68,7 +67,6 @@ import org.scijava.util.ClassUtils; import org.scijava.util.DoubleArray; import org.scijava.util.FloatArray; -import org.scijava.util.GenericUtils; import org.scijava.util.IntArray; import org.scijava.util.LongArray; import org.scijava.util.PrimitiveArray; @@ -87,6 +85,7 @@ public class ConvertServiceTest { @Before public void setUp() { + @SuppressWarnings("resource") final Context context = new Context(ConvertService.class); convertService = context.getService(ConvertService.class); } @@ -155,8 +154,14 @@ public void testArrays() { testIntechangeable(char[].class, CharArray.class); testIntechangeable(boolean[].class, BoolArray.class); - // Test that primitive [] can not be converted to mismatched PrimitiveArray - assertFalse(convertService.supports(int[].class, LongArray.class)); + // Test that primitive [] can be cross-converted to mismatched PrimitiveArray + assertTrue(convertService.supports(int[].class, LongArray.class)); + final LongArray crossConverted = // + convertService.convert(new int[] {2, 3, 5}, LongArray.class); + assertEquals(3, crossConverted.size()); + assertEquals(2L, (long) crossConverted.get(0)); + assertEquals(3L, (long) crossConverted.get(1)); + assertEquals(5L, (long) crossConverted.get(2)); // Test that lists can be converted to any primitive [] final List list = new ArrayList<>(); @@ -220,8 +225,10 @@ public void testCanConvert() { assertTrue(convertService.supports(HashSet.class, ArrayList.class)); assertTrue(convertService.supports(long.class, Date.class)); + // check conversion to collection type + assertTrue(convertService.supports(Collection.class, List.class)); + // check lack of conversion of various types w/o appropriate constructor - assertFalse(convertService.supports(Collection.class, List.class)); assertFalse(convertService.supports(int.class, Date.class)); } @@ -335,19 +342,11 @@ public void testConvertSubclass() { assertEquals("Bar", objectToHisList.get(1)); // ArrayList subclass to ArrayList subclass - // This surprisingly works due to type erasure... dangerous stuff. final NumberList hisToNumberList = convertService.convert(hisList, NumberList.class); assertEquals(2, hisToNumberList.size()); - assertEquals("Foo", hisToNumberList.get(0)); - assertEquals("Bar", hisToNumberList.get(1)); - try { - final Number n0 = hisToNumberList.get(0); - fail("expected ClassCastException but got: " + n0); - } - catch (final ClassCastException exc) { - // NB: Exception expected. - } + assertNull(hisToNumberList.get(0)); + assertNull(hisToNumberList.get(1)); } /** @@ -398,11 +397,15 @@ class Struct { assertEquals(123456789012.0, struct.myDoubles.get(0), 0.0); assertEquals(987654321098.0, struct.myDoubles.get(1), 0.0); - // Conversion to a list of strings (with no generic parameter) fails. + // Conversion to a list of strings (with no generic parameter) succeeds. setFieldValue(struct, "myStrings", longArray); - assertNull(struct.myStrings); + assertNotNull(struct.myStrings); + System.out.println(struct.myStrings); + assertEquals(2, struct.myStrings.size()); + assertEquals("123456789012", struct.myStrings.get(0)); + assertEquals("987654321098", struct.myStrings.get(1)); } /** @@ -457,16 +460,18 @@ class Struct { /** * Tests setting an incompatible element value for a primitive array. */ - @Test(expected = IllegalArgumentException.class) + @Test public void testBadPrimitiveArray() { class Struct { - @SuppressWarnings("unused") private int[] intArray; } final Struct struct = new Struct(); setFieldValue(struct, "intArray", "not an int array"); + assertNotNull(struct.intArray); + assertEquals(1, struct.intArray.length); + assertSame(0, struct.intArray[0]); } /** @@ -474,23 +479,39 @@ class Struct { * and a collection. */ @Test - public void testBadObjectElements() { + public void testIncompatibleCollections() { class Struct { private Double[] doubleArray; - private List stringList; - @SuppressWarnings("unused") - private Set nestedArray; + private List numberList; + private Set setOfIntegerArrays; } final Struct struct = new Struct(); - // Test abnormal behavior for an object array + // NB: DefaultConverter converts non-collection/array objects to + // collection/array objects, even if some or all of the constituent elements + // cannot be converted to the array/collection component/element type. + + // Test object to incompatible array type setFieldValue(struct, "doubleArray", "not a double array"); - assertEquals(null, struct.doubleArray[0]); + assertNotNull(struct.doubleArray); + assertEquals(1, struct.doubleArray.length); + assertNull(struct.doubleArray[0]); - // Test abnormal behavior for a list - setFieldValue(struct, "nestedArray", "definitely not a set of char arrays"); - assertNull(struct.stringList); + // Test object to incompatible List type + setFieldValue(struct, "numberList", "not actually a list of numbers"); + List expectedList = Arrays.asList((Number) null); + assertEquals(expectedList, struct.numberList); + + // Test object to incompatible Set type + setFieldValue(struct, "setOfIntegerArrays", // + "definitely not a set of Integer[]"); + assertNotNull(struct.setOfIntegerArrays); + assertEquals(1, struct.setOfIntegerArrays.size()); + Integer[] singleton = struct.setOfIntegerArrays.iterator().next(); + assertNotNull(singleton); + assertEquals(1, singleton.length); + assertNull(singleton[0]); } /** @@ -723,11 +744,8 @@ private List getValueList(final T... values) { * Helper class for testing conversion of one {@link ArrayList} subclass to * another. */ - public static class HisList extends ArrayList { - public HisList() { - super(); - } - public HisList(final Collection c) { + public static class HerList extends ArrayList { + public HerList(final Collection c) { super(c); } } @@ -736,8 +754,11 @@ public HisList(final Collection c) { * Helper class for testing conversion of one {@link ArrayList} subclass to * another. */ - public static class HerList extends ArrayList { - public HerList(final Collection c) { + public static class HisList extends ArrayList { + public HisList() { + super(); + } + public HisList(final Collection c) { super(c); } } diff --git a/src/test/java/org/scijava/convert/ConverterTest.java b/src/test/java/org/scijava/convert/ConverterTest.java index dd96e6191..3b29ac76f 100644 --- a/src/test/java/org/scijava/convert/ConverterTest.java +++ b/src/test/java/org/scijava/convert/ConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -57,13 +57,12 @@ public class ConverterTest { /** * Test case for the {@link NullConverter} */ - @SuppressWarnings("deprecation") @Test public void testNullConverter() { final NullConverter nc = new NullConverter(); assertFalse(nc.canConvert(Object.class, Object.class)); assertFalse(nc.canConvert(Object.class, (Type) Object.class)); - assertFalse(nc.canConvert((Class) null, Object.class)); + assertTrue(nc.canConvert((Class) null, Object.class)); assertTrue(nc.canConvert((Object) null, Object.class)); assertTrue(nc.canConvert((ConverterTest) null, ArrayList.class)); assertNull(nc.convert((Object) null, Object.class)); diff --git a/src/test/java/org/scijava/convert/DefaultConverterTest.java b/src/test/java/org/scijava/convert/DefaultConverterTest.java new file mode 100644 index 000000000..e591ae82b --- /dev/null +++ b/src/test/java/org/scijava/convert/DefaultConverterTest.java @@ -0,0 +1,279 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package org.scijava.convert; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests {@link DefaultConverter}. + * + * @author Curtis Rueden + * */ +public class DefaultConverterTest { + private DefaultConverter converter; + + @Before + public void setUp() { + converter = new DefaultConverter(); + } + + @Test + public void testObjectToObjectArray() { + Object o = new Object(); + assertTrue(converter.canConvert(o, Object[].class)); + Object[] result = converter.convert(o, Object[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertSame(o, result[0]); + } + + @Test + public void testIntToObjectArray() { + int v = 1; + assertTrue(converter.canConvert(v, Object[].class)); + Object[] result = converter.convert(v, Object[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertSame(v, result[0]); + } + + @Test + public void testIntToPrimitiveIntArray() { + int v = 2; + assertTrue(converter.supports(new ConversionRequest(v, int[].class))); + assertTrue(converter.canConvert(v, int[].class)); + int[] result = converter.convert(v, int[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertSame(v, result[0]); + } + + @Test + public void testIntToBoxedIntegerArray() { + int v = 3; + assertTrue(converter.canConvert(v, Integer[].class)); + Integer[] result = converter.convert(v, Integer[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertSame(v, result[0]); + } + + @Test + public void testByteToPrimitiveDoubleArray() { + byte v = 4; + assertTrue(converter.canConvert(v, double[].class)); + double[] result = converter.convert(v, double[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertEquals(v, result[0], 0.0); + } + + @Test + public void testByteToBoxedDoubleArray() { + byte v = 4; + assertTrue(converter.canConvert(v, Double[].class)); + Double[] result = converter.convert(v, Double[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertEquals(v, result[0], 0.0); + } + + @Test + public void testStringToObjectArray() { + String s = "Pumpernickel"; + assertTrue(converter.canConvert(s, Object[].class)); + Object[] result = converter.convert(s, Object[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertSame(s, result[0]); + } + + @Test + public void testStringToStringArray() { + String s = "smorgasbord"; + assertTrue(converter.canConvert(s, String[].class)); + String[] result = converter.convert(s, String[].class); + assertNotNull(result); + assertEquals(1, result.length); + assertSame(s, result[0]); + } + + @Test + public void testObjectToCollection() throws NoSuchFieldException { + @SuppressWarnings("unused") + class Struct { + private Collection collectionOfObjects; + private List listOfObjects; + private List listOfStrings; + private List listOfDoubles; + private Set setOfObjects; + } + + Type collectionOfObjectsType = Struct.class.getDeclaredField("collectionOfObjects").getGenericType(); + Type listOfObjectsType = Struct.class.getDeclaredField("listOfObjects").getGenericType(); + Type listOfStringsType = Struct.class.getDeclaredField("listOfStrings").getGenericType(); + Type listOfDoublesType = Struct.class.getDeclaredField("listOfDoubles").getGenericType(); + Type setOfObjectsType = Struct.class.getDeclaredField("setOfObjects").getGenericType(); + + Object o = new Object(); + + assertTrue(converter.canConvert(o, Collection.class)); + assertTrue(converter.canConvert(o, List.class)); + assertTrue(converter.canConvert(o, Set.class)); + + assertCollection(o, o, converter.convert(o, Collection.class), Collection.class); + assertCollection(o, o, converter.convert(o, List.class), List.class); + assertCollection(o, o, converter.convert(o, Set.class), Set.class); + + assertTrue(converter.canConvert(o, collectionOfObjectsType)); + assertTrue(converter.canConvert(o, listOfObjectsType)); + assertTrue(converter.canConvert(o, listOfStringsType)); + assertTrue(converter.canConvert(o, listOfDoublesType)); + assertTrue(converter.canConvert(o, setOfObjectsType)); + + assertCollection(o, o, converter.convert(o, collectionOfObjectsType), Collection.class); + assertCollection(o, o, converter.convert(o, listOfObjectsType), List.class); + assertCollection(o, o.toString(), converter.convert(o, listOfStringsType), List.class); + assertCollection(o, null, converter.convert(o, listOfDoublesType), List.class); + assertCollection(o, o, converter.convert(o, setOfObjectsType), Set.class); + + String s = "Thingamawhatsit"; + assertTrue(converter.canConvert(s, collectionOfObjectsType)); + assertTrue(converter.canConvert(s, listOfObjectsType)); + assertTrue(converter.canConvert(s, listOfStringsType)); + assertTrue(converter.canConvert(s, listOfDoublesType)); + assertTrue(converter.canConvert(s, setOfObjectsType)); + + assertCollection(s, s, converter.convert(s, collectionOfObjectsType), Collection.class); + assertCollection(s, s, converter.convert(s, listOfObjectsType), List.class); + assertCollection(s, s, converter.convert(s, listOfStringsType), List.class); + assertCollection(s, null, converter.convert(s, listOfDoublesType), List.class); + assertCollection(s, s, converter.convert(s, setOfObjectsType), Set.class); + + // TODO: Test more things, covering the equivalent of all *To*Array above. + } + + @Test + public void testNumberToNumber() { + double d = -5.6; + assertTrue(converter.canConvert(d, int.class)); + assertEquals(-5, converter.convert(d, int.class), 0.0); + // TODO: Test many more combinations of numeric types. + } + + @Test + public void testObjectToString() { + Object friendly = new Object() { + @Override + public String toString() { return "Hello"; } + }; + assertTrue(converter.canConvert(friendly, String.class)); + assertEquals("Hello", converter.convert(friendly, String.class)); + } + + @Test + public void testStringToCharacter() { + String plan = "Step 0: there is no plan"; + + assertTrue(converter.canConvert(plan, char.class)); + assertEquals('S', (char) converter.convert(plan, char.class)); + + assertTrue(converter.canConvert(plan, Character.class)); + assertEquals(new Character('S'), converter.convert(plan, Character.class)); + } + + @Test + public void testStringToCharacterArray() { + String plan = "Step 0: there is no plan"; + + assertTrue(converter.canConvert(plan, char[].class)); + final char[] converted = converter.convert(plan, char[].class); + assertArrayEquals(plan.toCharArray(), converted); + + // NB: Conversion to Character[] does not work the same way. + } + + private enum Gem { + RUBY, DIAMOND, EMERALD; + } + + @Test + public void testStringToEnum() { + assertTrue(converter.canConvert("RUBY", Gem.class)); + assertTrue(converter.canConvert("DIAMOND", Gem.class)); + assertTrue(converter.canConvert("EMERALD", Gem.class)); + assertTrue(converter.canConvert("QUARTZ", Gem.class)); + assertEquals(Gem.RUBY, converter.convert("RUBY", Gem.class)); + assertEquals(Gem.DIAMOND, converter.convert("DIAMOND", Gem.class)); + assertEquals(Gem.EMERALD, converter.convert("EMERALD", Gem.class)); + assertNull(converter.convert("QUARTZ", Gem.class)); + } + + public static class StringWrapper { + public String s; + public StringWrapper(String s) { this.s = s; } + } + + @Test + public void testConstructorConversion() { + String s = "Juggernaut"; + assertTrue(converter.canConvert(s, StringWrapper.class)); + assertFalse(converter.canConvert(7, StringWrapper.class)); + StringWrapper sw = converter.convert(s, StringWrapper.class); + assertNotNull(sw); + assertSame(s, sw.s); + } + + // -- Helper methods -- + + private static void assertCollection(Object o, Object expected, + Object collection, Class collectionClass) + { + assertNotNull(collection); + assertTrue(collectionClass.isInstance(collection)); + assertEquals(1, ((Collection) collection).size()); + Object actual = ((Collection) collection).iterator().next(); + if (o == expected) assertSame(expected, actual); + else assertEquals(expected, actual); // o was converted to element type + } +} diff --git a/src/test/java/org/scijava/convert/DelegateConverterTest.java b/src/test/java/org/scijava/convert/DelegateConverterTest.java index 045eabd6a..22470f4a3 100644 --- a/src/test/java/org/scijava/convert/DelegateConverterTest.java +++ b/src/test/java/org/scijava/convert/DelegateConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java index ed092262e..6f2f09886 100644 --- a/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/FileListConverterTest.java b/src/test/java/org/scijava/convert/FileListConverterTest.java index 632e82f4a..8d077c8a4 100644 --- a/src/test/java/org/scijava/convert/FileListConverterTest.java +++ b/src/test/java/org/scijava/convert/FileListConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -69,6 +69,7 @@ public void testStringToFileArrayConverter() { conv.convert(path, File[].class)[0]); assertEquals("Wrong file name", new File("C:\\temp"), conv.convert(path, File[].class)[1]); + assertEquals( 0, conv.convert( "", File[].class ).length ); } @Test diff --git a/src/test/java/org/scijava/convert/FileToPathConversionTest.java b/src/test/java/org/scijava/convert/FileToPathConversionTest.java new file mode 100644 index 000000000..ef020a279 --- /dev/null +++ b/src/test/java/org/scijava/convert/FileToPathConversionTest.java @@ -0,0 +1,85 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.convert; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.parse.ParseService; + +/** + * Tests conversion between {@link File}s and {@link Path}s. + * + * @author Gabriel Selzer + */ +public class FileToPathConversionTest { + + private ConvertService convertService; + private Context context; + + @Before + public void setUp() { + context = new Context(ParseService.class, ConvertService.class); + convertService = context.getService(ConvertService.class); + } + + @After + public void tearDown() { + context.dispose(); + } + + /** + * Tests the ability of to convert from {@link File} to {@link Path}. + */ + @Test + public void fileToPathConversion() { + File f = new File("tmp.java"); + assertTrue(convertService.supports(f, Path.class)); + Path p = convertService.convert(f, Path.class); + assertEquals(f.toPath(), p); + } + + @Test + public void pathToFileConversion() { + Path p = Paths.get("tmp.java"); + assertTrue(convertService.supports(p, File.class)); + File f = convertService.convert(p, File.class); + assertEquals(f.toPath(), p); + } + +} diff --git a/src/test/java/org/scijava/convert/FloatToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/FloatToBigDecimalConverterTest.java index 0be67f354..426f5af68 100644 --- a/src/test/java/org/scijava/convert/FloatToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/FloatToBigDecimalConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/FloatToDoubleConverterTest.java b/src/test/java/org/scijava/convert/FloatToDoubleConverterTest.java index 245ba6233..79ab0ddb1 100644 --- a/src/test/java/org/scijava/convert/FloatToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/FloatToDoubleConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/IntegerToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/IntegerToBigDecimalConverterTest.java index ffe7dc17b..8405d7489 100644 --- a/src/test/java/org/scijava/convert/IntegerToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToBigDecimalConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/IntegerToBigIntegerConverterTest.java b/src/test/java/org/scijava/convert/IntegerToBigIntegerConverterTest.java index 76690b449..5f58d847b 100644 --- a/src/test/java/org/scijava/convert/IntegerToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToBigIntegerConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/IntegerToDoubleConverterTest.java b/src/test/java/org/scijava/convert/IntegerToDoubleConverterTest.java index 9f4555224..a480aa4b2 100644 --- a/src/test/java/org/scijava/convert/IntegerToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToDoubleConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/IntegerToLongConverterTest.java b/src/test/java/org/scijava/convert/IntegerToLongConverterTest.java index 1552f8da7..e9ded24c7 100644 --- a/src/test/java/org/scijava/convert/IntegerToLongConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToLongConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/LongToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/LongToBigDecimalConverterTest.java index 929eb9bf7..4ea3bd95e 100644 --- a/src/test/java/org/scijava/convert/LongToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/LongToBigDecimalConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/LongToBigIntegerConverterTest.java b/src/test/java/org/scijava/convert/LongToBigIntegerConverterTest.java index 69fcb27bc..e5d8a412e 100644 --- a/src/test/java/org/scijava/convert/LongToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/LongToBigIntegerConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ShortToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/ShortToBigDecimalConverterTest.java index fb8dfae28..fe4aea074 100644 --- a/src/test/java/org/scijava/convert/ShortToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToBigDecimalConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ShortToBigIntegerConverterTest.java b/src/test/java/org/scijava/convert/ShortToBigIntegerConverterTest.java index d0c4d67ee..dcd7145b6 100644 --- a/src/test/java/org/scijava/convert/ShortToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToBigIntegerConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ShortToDoubleConverterTest.java b/src/test/java/org/scijava/convert/ShortToDoubleConverterTest.java index a7befa860..05b3e93c3 100644 --- a/src/test/java/org/scijava/convert/ShortToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToDoubleConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ShortToFloatConverterTest.java b/src/test/java/org/scijava/convert/ShortToFloatConverterTest.java index 2ce0c775b..e4fc125eb 100644 --- a/src/test/java/org/scijava/convert/ShortToFloatConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToFloatConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ShortToIntegerConverterTest.java b/src/test/java/org/scijava/convert/ShortToIntegerConverterTest.java index cb8505498..43d50e217 100644 --- a/src/test/java/org/scijava/convert/ShortToIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToIntegerConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/ShortToLongConverterTest.java b/src/test/java/org/scijava/convert/ShortToLongConverterTest.java index b9ca04268..03cb6e6d3 100644 --- a/src/test/java/org/scijava/convert/ShortToLongConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToLongConverterTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/convert/StringToArrayConverterTest.java b/src/test/java/org/scijava/convert/StringToArrayConverterTest.java new file mode 100644 index 000000000..2107a85a9 --- /dev/null +++ b/src/test/java/org/scijava/convert/StringToArrayConverterTest.java @@ -0,0 +1,273 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.convert; + +import static org.junit.Assert.assertArrayEquals; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.parse.ParseService; + +/** + * Tests {@link StringToArrayConverter}. + * + * @author Gabriel Selzer + */ +public class StringToArrayConverterTest { + + private final StringToArrayConverter converter = new StringToArrayConverter(); + private ConvertService convertService; + private Context context; + + @Before + public void setUp() { + context = new Context(ParseService.class, ConvertService.class); + context.inject(converter); + convertService = context.getService(ConvertService.class); + } + + @After + public void tearDown() { + context.dispose(); + } + + /** + * Tests the ability of {@link StringToArrayConverter} in converting to arrays + * of various types + */ + @Test + public void testArrayConversion() { + // Array types for array conversions + List> classes = Arrays.asList( // + byte[].class, // + Byte[].class, // + short[].class, // + Short[].class, // + int[].class, // + Integer[].class, // + long[].class, // + Long[].class, // + float[].class, // + Float[].class, // + double[].class, // + Double[].class // + ); + // String input + String s = "{0, 1, 2}"; + for (Class arrayClass : classes) { + // Ensure our Converter can do the conversion + Assert.assertTrue(converter.canConvert(s, arrayClass)); + // Do the conversion + Object converted = converter.convert(s, arrayClass); + // Ensure the output is the expected type + Assert.assertEquals(arrayClass, converted.getClass()); + Class c = arrayClass.getComponentType(); + for (int i = 0; i < 3; i++) { + // Ensure element correctness + Object expected = convertService.convert(i, c); + Assert.assertEquals(expected, Array.get(converted, i)); + } + } + } + + /** + * Tests the ability of {@link StringToArrayConverter} in converting + * 2-dimensional arrays + */ + @Test + public void test2DArrayConversion() { + String s = "{{0, 1}, {2, 3}}"; + Assert.assertTrue(converter.canConvert(s, byte[][].class)); + byte[][] actual = converter.convert(s, byte[][].class); + Assert.assertEquals(0, actual[0][0]); + Assert.assertEquals(1, actual[0][1]); + Assert.assertEquals(2, actual[1][0]); + Assert.assertEquals(3, actual[1][1]); + } + /** + * Tests the ability of {@link StringToArrayConverter} in converting + * 3-dimensional arrays + */ + @Test + public void test3DArrayConversion() { + String s = "{{{0, 1}, {1, 2}},{{1, 2}, {2, 3}}}"; + Assert.assertTrue(converter.canConvert(s, byte[][][].class)); + byte[][][] actual = converter.convert(s, byte[][][].class); + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + for (int k = 0; k < 2; k++) + Assert.assertEquals(i + j + k, actual[i][j][k]); + } + + /** + * Tests the ability of {@link StringToArrayConverter} in converting empty + * arrays + */ + @Test + public void testEmptyArrayConversion() { + String s = "{}"; + Assert.assertTrue(converter.canConvert(s, byte[].class)); + byte[] actual = converter.convert(s, byte[].class); + Assert.assertEquals(0, actual.length); + } + + /** + * Tests the special case of {@link String}s + */ + @Test + public void testStringArrayConversion() { + String[] expected = new String[] { // + "{foo", "bar}", // + "ha\nha", // + "foo,bar", // + "lol\"lol", // + "foo\\\"bar" // + }; + String converted = convertService.convert(expected, String.class); + Assert.assertEquals("{\"{foo\", \"bar}\", " + // + "\"ha\nha\", " + // + "\"foo,bar\", " + // + "\"lol\\\"lol\", " + // + "\"foo\\\\\\\"bar\"}", converted); + String[] actual = convertService.convert(converted, String[].class); + Assert.assertArrayEquals(expected, actual); + } + + /** + * Tests the special case of {@link Character}s + */ + @Test + public void testCharacterArrayConversion() { + Character[] expected = new Character[] { // + 's', // + '\n', // + ',', // + '{', // + '}' // + }; + String converted = convertService.convert(expected, String.class); + Assert.assertEquals("{\"s\", \"\n\", \",\", \"{\", \"}\"}", converted); + Character[] actual = convertService.convert(converted, Character[].class); + Assert.assertArrayEquals(expected, actual); + } + + @Test + public void testStringToDoubleArraySingleValue() { + assertArrayEquals(new double[] {5}, + converter.convert("5", double[].class), 0); + assertArrayEquals(new Double[] {6d}, + converter.convert("6", Double[].class)); + assertArrayEquals(new double[][] {{7}}, + converter.convert("7", double[][].class)); + assertArrayEquals(new Double[][] {{8d}}, + converter.convert("8", Double[][].class)); + + assertArrayEquals(new double[] {0}, + converter.convert("spinach", double[].class), 0); + assertArrayEquals(new Double[] {null}, + converter.convert("kale", Double[].class)); + assertArrayEquals(new double[][] {{0}}, + converter.convert("broccoli", double[][].class)); + assertArrayEquals(new Double[][] {{null}}, + converter.convert("lettuce", Double[][].class)); + } + + @Test + public void testStringToDoubleArray1D() { + // all numbers + assertArrayEquals(new double[] {0, 1, 2, 3}, + converter.convert("{0, 1, 2, 3}", double[].class), 0); + assertArrayEquals(new Double[] {7d, 11d}, + converter.convert("{7, 11}", Double[].class)); + assertArrayEquals(new Double[] {0d, 1d, 2d, 3d}, + converter.convert("{0, 1, 2, 3}", Double[].class)); + + // mixed numbers/non-numbers + assertArrayEquals(new double[] {0, 1, 0, 3}, + converter.convert("{0, 1, kumquat, 3}", double[].class), 0); + assertArrayEquals(new Double[] {4d, null, 5d}, + converter.convert("{4, eggplant, 5}", Double[].class)); + + // all non-numbers + assertArrayEquals(new double[] {0, 0, 0}, + converter.convert("{uno, dos, tres}", double[].class), 0); + assertArrayEquals(new Double[] {null, null, null, null}, + converter.convert("{cuatro, cinco, seis, siete}", Double[].class)); + } + + @Test + public void testStringToDoubleArray2D() { + // all numbers + assertArrayEquals(new double[][] {{0, 1}, {2, 3, 4}}, + converter.convert("{{0, 1}, {2, 3, 4}}", double[][].class)); + assertArrayEquals(new Double[][] {{7d, 11d}, {13d, 17d, 19d}}, + converter.convert("{{7, 11}, {13, 17, 19}}", Double[][].class)); + assertArrayEquals(new Double[][] {{0d, 1d}, {2d, 3d}}, + converter.convert("{{0, 1}, {2, 3}}", Double[][].class)); + + // mixed numbers/non-numbers + assertArrayEquals(new double[][] {{0, 1}, {0, 3}}, + converter.convert("{{0, 1}, {kumquat, 3}}", double[][].class)); + assertArrayEquals(new Double[][] {{4d}, {null, 5d}, {null}}, + converter.convert("{{4}, {eggplant, 5}, {squash}}", Double[][].class)); + + // all non-numbers + assertArrayEquals(new double[][] {{0}, {0, 0}}, + converter.convert("{{uno}, {dos, tres}}", double[][].class)); + assertArrayEquals(new Double[][] {{null, null}, {null, null}}, + converter.convert("{{cuatro, cinco}, {seis, siete}}", Double[][].class)); + } + + @Test + public void testStringToDoubleArray3D() { + final Random r = new Random(0xDA7ABA5E); + final double[][][] ds = new double[r.nextInt(10)][][]; + for (int i=0; i { +} diff --git a/src/test/java/org/scijava/event/bushe/EBTestCounter.java b/src/test/java/org/scijava/event/bushe/EBTestCounter.java new file mode 100644 index 000000000..8ebf75160 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/EBTestCounter.java @@ -0,0 +1,10 @@ +package org.scijava.event.bushe; + +/** + * @author Michael Bushe + * @since Nov 19, 2005 11:12:35 PM + */ +public class EBTestCounter { + public int eventsHandledCount; + public int subscribeExceptionCount; +} diff --git a/src/test/java/org/scijava/event/bushe/EDTUtil.java b/src/test/java/org/scijava/event/bushe/EDTUtil.java new file mode 100644 index 000000000..c74d4846f --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/EDTUtil.java @@ -0,0 +1,36 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.scijava.event.bushe; + +import java.awt.EventQueue; +import java.awt.Toolkit; + +/** + * + * @author Michael Bushe + */ +public class EDTUtil { + + /** + * Since we are using the event bus from a non-awt thread, stay alive for a sec to give time for the EDT to start and + * post the message + */ + public static void waitForEDT() { + EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + long start = System.currentTimeMillis(); + do { + //wait at least once - plenty of time for the event sent to the queue to get there + long now = System.currentTimeMillis(); + if (now > start + (1000*5) ) { + throw new RuntimeException("Waited too long for the EDT to finish."); + } + try { + Thread.sleep(100); + } catch (Throwable e) { + } + } while(eventQueue.peekEvent() != null); + } +} diff --git a/src/test/java/org/scijava/event/bushe/GenericReflection.java b/src/test/java/org/scijava/event/bushe/GenericReflection.java new file mode 100644 index 000000000..d3d2954b3 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/GenericReflection.java @@ -0,0 +1,125 @@ +package org.scijava.event.bushe; + +import java.lang.reflect.TypeVariable; + +import java.lang.reflect.*; +import java.io.*; + +/** + * From OReilly Book Java Generics + */ +public class GenericReflection { + DataRequestEvent dre; + private final static PrintStream out = System.out; + public static void printSuperclass (Type sup) { + if (sup != null && !sup.equals(Object.class)) { + out.print("extends "); + printType(sup); + out.println(); + } + } + public static void printInterfaces (Type[] implementations) { + if (implementations != null && implementations.length > 0) { + out.print("implements "); + int i = 0; + for (Type impl : implementations) { + if (i++ > 0) out.print(","); + printType(impl); + } + out.println(); + } + } + public static void printTypeParameters (TypeVariable[] vars) { + if (vars != null && vars.length > 0) { + out.print("<"); + int i = 0; + for (TypeVariable var : vars) { + if (i++ > 0) out.print(","); + out.print(var.getName()); + printBounds(var.getBounds()); + } + out.print(">"); + } + } + public static void printBounds (Type[] bounds) { + if (bounds != null && bounds.length > 0 + && !(bounds.length==1 && bounds[0]==Object.class)) { + out.print(" extends "); + int i = 0; + for (Type bound : bounds) { + if (i++ > 0) out.print("&"); + printType(bound); + } + } + } + public static void printParams (Type[] types) { + if (types != null && types.length > 0) { + out.print("<"); + int i = 0; + for (Type type : types) { + if (i++ > 0) out.print(","); + printType(type); + } + out.print(">"); + } + } + public static void printType (Type type) { + if (type instanceof Class) { + Class c = (Class)type; + out.print(c.getName()); + } else if (type instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType)type; + Class c = (Class)p.getRawType(); + Type o = p.getOwnerType(); + if (o != null) { printType(o); out.print("."); } + out.print(c.getName()); + printParams(p.getActualTypeArguments()); + } else if (type instanceof TypeVariable) { + TypeVariable v = (TypeVariable)type; + out.print(v.getName()); + } else if (type instanceof GenericArrayType) { + GenericArrayType a = (GenericArrayType)type; + printType(a.getGenericComponentType()); + out.print("[]"); + } else if (type instanceof WildcardType) { + WildcardType w = (WildcardType)type; + Type[] upper = w.getUpperBounds(); + Type[] lower = w.getLowerBounds(); + if (upper.length==1 && lower.length==0) { + out.print("? extends "); + printType(upper[0]); + } else if (upper.length==0 && lower.length==1) { + out.print("? super "); + printType(lower[0]); + } else assert false; + } + } + public static void printClass (Class c) { + out.print("class "); + out.print(c.getName()); + printTypeParameters(c.getTypeParameters()); + out.println(); + printSuperclass(c.getGenericSuperclass()); + printInterfaces(c.getGenericInterfaces()); + /* + out.println("{"); + for (Field f : c.getFields()) { + out.println(" "+f.toGenericString()+";"); + } + for (Constructor k : c.getConstructors()) { + out.println(" "+k.toGenericString()+";"); + } + for (Method m : c.getMethods()) { + out.println(" "+m.toGenericString()+";"); + } + out.println("}"); + */ + } + public static void main (String[] args) throws ClassNotFoundException { + for (String name : args) { + Class c = Class.forName(name); + printClass(c); + } + } +} + diff --git a/src/test/java/org/scijava/event/bushe/MyData.java b/src/test/java/org/scijava/event/bushe/MyData.java new file mode 100644 index 000000000..43be650c8 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/MyData.java @@ -0,0 +1,17 @@ +package org.scijava.event.bushe; + +/** + * Intended to answer this post: + * https://eventbus.dev.java.net/servlets/ProjectForumMessageView?messageID=30702&forumID=1834 + */ +public class MyData { + private String classification = "foo"; + + public String getClassification() { + return classification; + } + + public void setClassification(String classification) { + this.classification = classification; + } +} diff --git a/src/test/java/org/scijava/event/bushe/SubscriberForTest.java b/src/test/java/org/scijava/event/bushe/SubscriberForTest.java new file mode 100644 index 000000000..2fac88e57 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/SubscriberForTest.java @@ -0,0 +1,43 @@ +package org.scijava.event.bushe; + +import java.util.Date; + +/** + * @author Michael Bushe + * @since Nov 19, 2005 11:01:06 PM + */ +public class SubscriberForTest implements EventSubscriber { + private boolean throwException; + private Long waitTime; + private EBTestCounter testDefaultEventService; + Date callTime = null; + + public SubscriberForTest(EBTestCounter testDefaultEventService, Long waitTime) { + this.testDefaultEventService = testDefaultEventService; + this.waitTime = waitTime; + } + + public SubscriberForTest(EBTestCounter testDefaultEventService, boolean throwException) { + this.testDefaultEventService = testDefaultEventService; + this.throwException = throwException; + } + + public void onEvent(Object evt) { + callTime = new Date(); + if (waitTime != null) { + try { + Thread.sleep(waitTime.longValue()); + } catch (InterruptedException e) { + } + } + testDefaultEventService.eventsHandledCount++; + if (throwException) { + testDefaultEventService.subscribeExceptionCount++; + throw new IllegalArgumentException(); + } + } + + public boolean equals(Object obj) { + return (this == obj); + } +} diff --git a/src/test/java/org/scijava/event/bushe/SubscriberForTesting.java b/src/test/java/org/scijava/event/bushe/SubscriberForTesting.java new file mode 100644 index 000000000..a0a0fdf2c --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/SubscriberForTesting.java @@ -0,0 +1,5 @@ +package org.scijava.event.bushe; + +public interface SubscriberForTesting { + long getTimesCalled(); +} diff --git a/src/test/java/org/scijava/event/bushe/TestPerformance.java b/src/test/java/org/scijava/event/bushe/TestPerformance.java new file mode 100644 index 000000000..a936200ee --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/TestPerformance.java @@ -0,0 +1,75 @@ +package org.scijava.event.bushe; + +import junit.framework.TestCase; +import junit.framework.Assert; + +import javax.swing.*; +import java.awt.*; +import java.awt.List; +import java.util.*; + +/** + * For proving performance. + */ +public class TestPerformance extends TestCase { + private EventSubscriber doNothingSubscriber = new EventSubscriber() { + public void onEvent(Object event) { + } + }; + + private EventTopicSubscriber doNothingTopicSubscriber = new EventTopicSubscriber() { + public void onEvent(String topic, Object payload) { + } + }; + + public void testClassPerformance() { + ThreadSafeEventService eventService = new ThreadSafeEventService(); + Class[] classes = {Color.class, String.class, JTextField.class, List.class, JButton.class, + Boolean.class, Integer.class, Boolean.class, Set.class, Date.class}; + Object[] payloads = {Color.BLUE, "foo", new JTextField(), new ArrayList(), new JButton(), + Boolean.TRUE, 35, 36L, new HashSet(), new Date()}; + for (Class aClass : classes) { + eventService.subscribe(aClass, doNothingSubscriber); + } + + long start = System.currentTimeMillis(); + int count = 100000; + for (int i=0; i < count; i++) { + for (Object payload : payloads) { + eventService.publish(payload); + } + } + long end = System.currentTimeMillis(); + long duration = (end - start)/1000; + int numPubs = count * payloads.length; + System.out.println("Time for "+ numPubs +" publications with subscribers to "+classes.length + +" different classes subscribed to was "+ duration +" s. Average:"+((double)duration/(double)numPubs)); + Assert.assertTrue("Things are slowing down, "+numPubs+" class publications used to take 3.3 seconds, it now takes " +duration, duration < 7); + } + + public void testStringPerformance() { + ThreadSafeEventService eventService = new ThreadSafeEventService(); + String[] strings = {"Color", "String", "JTextField", "List", "JButton", + "Boolean", "Integer", "Boolean", "Set", "Date"}; + Object[] payloads = {Color.BLUE, "foo", new JTextField(), new ArrayList(), new JButton(), + Boolean.TRUE, 35, 36L, new HashSet(), new Date()}; + for (String aString : strings) { + eventService.subscribe(aString, doNothingTopicSubscriber); + } + + long start = System.currentTimeMillis(); + int count = 100000; + for (int i=0; i < count; i++) { + for (int j=0; j < strings.length; j++) { + eventService.publish(strings[j], payloads[j]); + } + } + long end = System.currentTimeMillis(); + long duration = (end - start)/1000; + int numPubs = count * payloads.length; + System.out.println("Time for "+ numPubs +" topic publications with topic subscribers to "+ strings.length + +" different strings subscribed to was "+ duration +" s. Average:"+((double)duration/(double)numPubs)); + Assert.assertTrue("Things are slowing down, "+numPubs+" string publications used to take 1.3 seconds, it now takes "+duration, duration < 4); + } + +} diff --git a/src/test/java/org/scijava/event/bushe/TopicSubscriberForTest.java b/src/test/java/org/scijava/event/bushe/TopicSubscriberForTest.java new file mode 100644 index 000000000..3b7836df8 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/TopicSubscriberForTest.java @@ -0,0 +1,35 @@ +package org.scijava.event.bushe; + +/** + * @author Michael Bushe + * @since Nov 19, 2005 11:00:53 PM + */ +public class TopicSubscriberForTest implements EventTopicSubscriber { + private boolean throwException; + private Long waitTime; + private EBTestCounter testDefaultEventService; + + public TopicSubscriberForTest(EBTestCounter testDefaultEventService, Long waitTime) { + this.testDefaultEventService = testDefaultEventService; + this.waitTime = waitTime; + } + + public TopicSubscriberForTest(EBTestCounter testDefaultEventService, boolean throwException) { + this.testDefaultEventService = testDefaultEventService; + this.throwException = throwException; + } + + public void onEvent(String topic, Object evt) { + if (waitTime != null) { + try { + Thread.sleep(waitTime.longValue()); + } catch (InterruptedException e) { + } + } + testDefaultEventService.eventsHandledCount++; + if (throwException) { + testDefaultEventService.subscribeExceptionCount++; + throw new IllegalArgumentException(); + } + } +} diff --git a/src/test/java/org/scijava/event/bushe/VetoEventListenerForTest.java b/src/test/java/org/scijava/event/bushe/VetoEventListenerForTest.java new file mode 100644 index 000000000..81a481185 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/VetoEventListenerForTest.java @@ -0,0 +1,24 @@ +package org.scijava.event.bushe; + +/** + * @author Michael Bushe + * @since Nov 19, 2005 11:00:42 PM + */ +public class VetoEventListenerForTest implements VetoEventListener { + private boolean throwException; + + public VetoEventListenerForTest() { + this(false); + } + + public VetoEventListenerForTest(boolean throwException) { + this.throwException = throwException; + } + + public boolean shouldVeto(Object evt) { + if (throwException) { + throw new IllegalArgumentException("veto ex"); + } + return true; + } +} diff --git a/src/test/java/org/scijava/event/bushe/VetoTopicEventListenerForTest.java b/src/test/java/org/scijava/event/bushe/VetoTopicEventListenerForTest.java new file mode 100644 index 000000000..af8bf79e5 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/VetoTopicEventListenerForTest.java @@ -0,0 +1,24 @@ +package org.scijava.event.bushe; + +/** + * @author Michael Bushe + * @since Nov 19, 2005 11:00:42 PM + */ +public class VetoTopicEventListenerForTest implements VetoTopicEventListener { + private boolean throwException; + + public VetoTopicEventListenerForTest() { + this(false); + } + + VetoTopicEventListenerForTest(boolean throwException) { + this.throwException = throwException; + } + + public boolean shouldVeto(String topic, Object data) { + if (throwException) { + throw new IllegalArgumentException("veto ex"); + } + return true; + } +} diff --git a/src/test/java/org/scijava/input/AcceleratorTest.java b/src/test/java/org/scijava/input/AcceleratorTest.java new file mode 100644 index 000000000..762489389 --- /dev/null +++ b/src/test/java/org/scijava/input/AcceleratorTest.java @@ -0,0 +1,82 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.input; + +import org.junit.Test; +import org.scijava.util.PlatformUtils; + +import static org.junit.Assert.*; + +/** + * Tests {@link Accelerator}. + * + * @author Curtis Rueden + */ +public class AcceleratorTest { + + /** Tests {@link Accelerator#create}. */ + @Test + public void testCreate() { + assertAccelerator("*", KeyCode.ASTERISK, false, false, false, false, false); + assertAccelerator("0", KeyCode.NUM0, false, false, false, false, false); + assertAccelerator("NUMPAD_0", KeyCode.NUMPAD_0, false, false, false, false, false); + assertAccelerator("+", KeyCode.PLUS, false, false, false, false, false); + assertAccelerator("shift minus", KeyCode.MINUS, false, false, false, false, true); + assertAccelerator("ctrl shift +", KeyCode.PLUS, false, false, true, false, true); + assertAccelerator("meta /", KeyCode.SLASH, false, false, false, true, false); + assertAccelerator("alt altGr ctrl meta shift a", KeyCode.A, true, true, true, true, true); + + // Test caret shortcut symbol. + final boolean macos = PlatformUtils.isMac(); + assertAccelerator("^Z", KeyCode.Z, false, false, !macos, macos, false); + } + + private void assertAccelerator(String shortcut, + KeyCode keyCode, + final boolean alt, + final boolean altGr, + final boolean ctrl, + final boolean meta, + final boolean shift) + { + Accelerator acc = Accelerator.create(shortcut); + assertEquals(acc.getKeyCode(), keyCode); + InputModifiers mods = acc.getModifiers(); + assertNotNull(mods); + assertEquals(alt, mods.isAltDown()); + assertEquals(altGr, mods.isAltGrDown()); + assertEquals(ctrl, mods.isCtrlDown()); + assertEquals(meta, mods.isMetaDown()); + assertEquals(shift, mods.isShiftDown()); + assertFalse(mods.isLeftButtonDown()); + assertFalse(mods.isMiddleButtonDown()); + assertFalse(mods.isRightButtonDown()); + } +} diff --git a/src/test/java/org/scijava/input/KeyCodeTest.java b/src/test/java/org/scijava/input/KeyCodeTest.java new file mode 100644 index 000000000..e094dc551 --- /dev/null +++ b/src/test/java/org/scijava/input/KeyCodeTest.java @@ -0,0 +1,91 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.input; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +/** + * Tests {@link KeyCode}. + * + * @author Curtis Rueden + */ +public class KeyCodeTest { + + @Test + public void testGetInt() { + assertEquals(KeyCode.ENTER, KeyCode.get(0x0a)); + assertEquals(KeyCode.PLUS, KeyCode.get(0x0209)); + assertEquals(KeyCode.NUM0, KeyCode.get(0x30)); + assertEquals(KeyCode.NUMPAD_0, KeyCode.get(0x60)); + assertEquals(KeyCode.A, KeyCode.get(0x41)); + assertEquals(KeyCode.Z, KeyCode.get(0x5a)); + + assertEquals(KeyCode.UNDEFINED, KeyCode.get(0xaaaa)); + assertEquals(KeyCode.UNDEFINED, KeyCode.get(0xffff)); + } + + @Test + public void testGetChar() { + assertEquals(KeyCode.ENTER, KeyCode.get('\n')); + assertEquals(KeyCode.ENTER, KeyCode.get('\r')); + assertEquals(KeyCode.PLUS, KeyCode.get('+')); + assertEquals(KeyCode.NUM0, KeyCode.get('0')); + assertEquals(KeyCode.A, KeyCode.get('a')); + assertEquals(KeyCode.A, KeyCode.get('A')); + assertEquals(KeyCode.Z, KeyCode.get('z')); + assertEquals(KeyCode.Z, KeyCode.get('Z')); + + assertEquals(KeyCode.UNDEFINED, KeyCode.get('\0')); + + // The following should maybe be considered a bug. + assertEquals(KeyCode.UNDEFINED, KeyCode.get('|')); + } + + @Test + public void testGetString() { + assertEquals(KeyCode.PLUS, KeyCode.get("PLUS")); + assertEquals(KeyCode.NUM0, KeyCode.get("NUM0")); + assertEquals(KeyCode.NUMPAD_0, KeyCode.get("NUMPAD_0")); + assertEquals(KeyCode.A, KeyCode.get("A")); + assertEquals(KeyCode.Z, KeyCode.get("Z")); + + // The next ones should fall back to get(char). + assertEquals(KeyCode.NUM0, KeyCode.get("0")); + assertEquals(KeyCode.A, KeyCode.get("a")); + assertEquals(KeyCode.Z, KeyCode.get("z")); + + assertEquals(KeyCode.UNDEFINED, KeyCode.get("UNDEFINED")); + assertEquals(KeyCode.UNDEFINED, KeyCode.get("")); + assertEquals(KeyCode.UNDEFINED, KeyCode.get("aa")); + assertEquals(KeyCode.UNDEFINED, KeyCode.get("asdf")); + } +} diff --git a/src/test/java/org/scijava/io/ByteArrayByteBankTest.java b/src/test/java/org/scijava/io/ByteArrayByteBankTest.java index e7ee584eb..e648071ca 100644 --- a/src/test/java/org/scijava/io/ByteArrayByteBankTest.java +++ b/src/test/java/org/scijava/io/ByteArrayByteBankTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/ByteBankTest.java b/src/test/java/org/scijava/io/ByteBankTest.java index 2c69cd595..8956d1b01 100644 --- a/src/test/java/org/scijava/io/ByteBankTest.java +++ b/src/test/java/org/scijava/io/ByteBankTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/IOServiceTest.java b/src/test/java/org/scijava/io/IOServiceTest.java index 68ceb121a..6ac3b1cb9 100644 --- a/src/test/java/org/scijava/io/IOServiceTest.java +++ b/src/test/java/org/scijava/io/IOServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/TypedIOServiceTest.java b/src/test/java/org/scijava/io/TypedIOServiceTest.java index 8e100352c..d1268e2e3 100644 --- a/src/test/java/org/scijava/io/TypedIOServiceTest.java +++ b/src/test/java/org/scijava/io/TypedIOServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/event/DataEventTest.java b/src/test/java/org/scijava/io/event/DataEventTest.java index 477f6be79..5318ea04e 100644 --- a/src/test/java/org/scijava/io/event/DataEventTest.java +++ b/src/test/java/org/scijava/io/event/DataEventTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/BytesHandleTest.java b/src/test/java/org/scijava/io/handle/BytesHandleTest.java index 9e023e1be..23c8631bc 100644 --- a/src/test/java/org/scijava/io/handle/BytesHandleTest.java +++ b/src/test/java/org/scijava/io/handle/BytesHandleTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/DataHandleEdgeCaseTests.java b/src/test/java/org/scijava/io/handle/DataHandleEdgeCaseTests.java index abc9d99a8..4ac6dfe70 100644 --- a/src/test/java/org/scijava/io/handle/DataHandleEdgeCaseTests.java +++ b/src/test/java/org/scijava/io/handle/DataHandleEdgeCaseTests.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/DataHandleTest.java b/src/test/java/org/scijava/io/handle/DataHandleTest.java index d62bdca7f..8bdd827a7 100644 --- a/src/test/java/org/scijava/io/handle/DataHandleTest.java +++ b/src/test/java/org/scijava/io/handle/DataHandleTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/DataHandlesTest.java b/src/test/java/org/scijava/io/handle/DataHandlesTest.java index 7aa81bfb1..003f25265 100644 --- a/src/test/java/org/scijava/io/handle/DataHandlesTest.java +++ b/src/test/java/org/scijava/io/handle/DataHandlesTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/FileHandleTest.java b/src/test/java/org/scijava/io/handle/FileHandleTest.java index 8b405416c..83a65cb79 100644 --- a/src/test/java/org/scijava/io/handle/FileHandleTest.java +++ b/src/test/java/org/scijava/io/handle/FileHandleTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java index 13a93571e..458faa566 100644 --- a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java +++ b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java index bd1a9ed14..f7bd863f2 100644 --- a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java +++ b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java b/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java index b9295187e..380c789bb 100644 --- a/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java +++ b/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/location/BytesLocationTest.java b/src/test/java/org/scijava/io/location/BytesLocationTest.java index f7f26c67e..28cffaccf 100644 --- a/src/test/java/org/scijava/io/location/BytesLocationTest.java +++ b/src/test/java/org/scijava/io/location/BytesLocationTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/location/FileLocationResolverTest.java b/src/test/java/org/scijava/io/location/FileLocationResolverTest.java index f3326660a..00a68d04a 100644 --- a/src/test/java/org/scijava/io/location/FileLocationResolverTest.java +++ b/src/test/java/org/scijava/io/location/FileLocationResolverTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/location/FileLocationTest.java b/src/test/java/org/scijava/io/location/FileLocationTest.java index cb7562977..d558bb338 100644 --- a/src/test/java/org/scijava/io/location/FileLocationTest.java +++ b/src/test/java/org/scijava/io/location/FileLocationTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/location/LocationServiceTest.java b/src/test/java/org/scijava/io/location/LocationServiceTest.java index feb628fa4..1943a0f35 100644 --- a/src/test/java/org/scijava/io/location/LocationServiceTest.java +++ b/src/test/java/org/scijava/io/location/LocationServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,6 +30,7 @@ package org.scijava.io.location; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; @@ -43,6 +44,7 @@ * Tests {@link LocationService}. * * @author Gabriel Einsdorf + * @author Curtis Rueden */ public class LocationServiceTest { @@ -60,6 +62,23 @@ public void testResolve() throws URISyntaxException { assertEquals(uri, loc.resolve(uri.toString()).getURI()); } + @Test + public void testResolveWindowsPath() throws URISyntaxException { + final Context ctx = new Context(LocationService.class); + final LocationService loc = ctx.getService(LocationService.class); + + String pSlash = "C:/Windows/FilePath/image.tif"; + final Location locSlash = loc.resolve(pSlash); + assertTrue(locSlash instanceof FileLocation); + + String pBackslash = pSlash.replace('/', '\\'); + final Location locBackslash = loc.resolve(pBackslash); + assertTrue(locBackslash instanceof FileLocation); + + final Location locSlashURI = loc.resolve(new URI(pSlash)); + assertNull(locSlashURI); + } + @Test public void testFallBack() throws URISyntaxException { final Context ctx = new Context(LocationService.class); diff --git a/src/test/java/org/scijava/io/location/URILocationTest.java b/src/test/java/org/scijava/io/location/URILocationTest.java index 08c886467..9bb1bfcc7 100644 --- a/src/test/java/org/scijava/io/location/URILocationTest.java +++ b/src/test/java/org/scijava/io/location/URILocationTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/location/URLLocationTest.java b/src/test/java/org/scijava/io/location/URLLocationTest.java index 9b939f4a1..d3d0e24c0 100644 --- a/src/test/java/org/scijava/io/location/URLLocationTest.java +++ b/src/test/java/org/scijava/io/location/URLLocationTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/io/nio/ByteBufferByteBankTest.java b/src/test/java/org/scijava/io/nio/ByteBufferByteBankTest.java index 90919ed48..cd904fe7f 100644 --- a/src/test/java/org/scijava/io/nio/ByteBufferByteBankTest.java +++ b/src/test/java/org/scijava/io/nio/ByteBufferByteBankTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/log/CallingClassUtilsTest.java b/src/test/java/org/scijava/log/CallingClassUtilsTest.java index a5893c905..a2aa73763 100644 --- a/src/test/java/org/scijava/log/CallingClassUtilsTest.java +++ b/src/test/java/org/scijava/log/CallingClassUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/log/DefaultLoggerTest.java b/src/test/java/org/scijava/log/DefaultLoggerTest.java index 865e306aa..d19a8189b 100644 --- a/src/test/java/org/scijava/log/DefaultLoggerTest.java +++ b/src/test/java/org/scijava/log/DefaultLoggerTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/log/LogMessageTest.java b/src/test/java/org/scijava/log/LogMessageTest.java index 733e28ff5..40bf7aeab 100644 --- a/src/test/java/org/scijava/log/LogMessageTest.java +++ b/src/test/java/org/scijava/log/LogMessageTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/log/LogServiceTest.java b/src/test/java/org/scijava/log/LogServiceTest.java index fccbc18fb..b0fe0e83c 100644 --- a/src/test/java/org/scijava/log/LogServiceTest.java +++ b/src/test/java/org/scijava/log/LogServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/log/LogSourceTest.java b/src/test/java/org/scijava/log/LogSourceTest.java index 848a5e17d..d9bed1ef4 100644 --- a/src/test/java/org/scijava/log/LogSourceTest.java +++ b/src/test/java/org/scijava/log/LogSourceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/log/StderrLogServiceTest.java b/src/test/java/org/scijava/log/StderrLogServiceTest.java index 00d3a698b..6745f0aaf 100644 --- a/src/test/java/org/scijava/log/StderrLogServiceTest.java +++ b/src/test/java/org/scijava/log/StderrLogServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/log/TestLogListener.java b/src/test/java/org/scijava/log/TestLogListener.java index ef6224cfa..8368e0142 100644 --- a/src/test/java/org/scijava/log/TestLogListener.java +++ b/src/test/java/org/scijava/log/TestLogListener.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/main/MainServiceTest.java b/src/test/java/org/scijava/main/MainServiceTest.java index e96794ed8..f1bc97136 100644 --- a/src/test/java/org/scijava/main/MainServiceTest.java +++ b/src/test/java/org/scijava/main/MainServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/main/run/MainCodeRunnerTest.java b/src/test/java/org/scijava/main/run/MainCodeRunnerTest.java index eaf05da9b..523fc3bf8 100644 --- a/src/test/java/org/scijava/main/run/MainCodeRunnerTest.java +++ b/src/test/java/org/scijava/main/run/MainCodeRunnerTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/menu/MenuServiceTest.java b/src/test/java/org/scijava/menu/MenuServiceTest.java index d3c7428d5..ea23052c8 100644 --- a/src/test/java/org/scijava/menu/MenuServiceTest.java +++ b/src/test/java/org/scijava/menu/MenuServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/menu/ShadowMenuTest.java b/src/test/java/org/scijava/menu/ShadowMenuTest.java index f24093192..8972dacfa 100644 --- a/src/test/java/org/scijava/menu/ShadowMenuTest.java +++ b/src/test/java/org/scijava/menu/ShadowMenuTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/module/ModuleServiceTest.java b/src/test/java/org/scijava/module/ModuleServiceTest.java index b7f94ca7a..e0fee870f 100644 --- a/src/test/java/org/scijava/module/ModuleServiceTest.java +++ b/src/test/java/org/scijava/module/ModuleServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,11 +29,15 @@ package org.scijava.module; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ExecutionException; @@ -42,6 +46,7 @@ import org.junit.Before; import org.junit.Test; import org.scijava.Context; +import org.scijava.parse.ParseService; /** * Tests {@link ModuleService}. @@ -54,7 +59,7 @@ public class ModuleServiceTest { @Before public void setUp() { - final Context context = new Context(ModuleService.class); + final Context context = new Context(ModuleService.class, ParseService.class); moduleService = context.service(ModuleService.class); } @@ -158,6 +163,67 @@ public void testGetSingleInput() throws ModuleException { assertSame(info.getInput("double2"), singleDouble); } + @Test + public void testSaveAndLoad() { + List objects = Arrays.asList( // + new double[] {}, // + new double[] { 1., 2., 3. }, // + new Double[] {}, // + new Double[] { 1., 2., 3. } // + ); + objects.forEach(this::assertParamSavedAndLoaded); + } + + private void assertParamSavedAndLoaded(T object) { + @SuppressWarnings("unchecked") + Class c = (Class) object.getClass(); + // Get a ModuleItem of the right type + MutableModule m = new DefaultMutableModule(); + m.getInfo().addInput(new DefaultMutableModuleItem<>(m, "a", c)); + final ModuleItem item = moduleService.getSingleInput(m, c); + // Save a value to the ModuleItem + moduleService.save(item, object); + // Load that value from the ModuleItem + Object actual = moduleService.load(item); + // Assert equality + if (object.getClass().isArray()) assertArrayEquality(object, actual); + else assertEquals(object, actual); + } + + private void assertArrayEquality(Object arr1, Object arr2) { + // Ensure that both Objects are arrays of the same type! + assertEquals(arr1.getClass(), arr2.getClass()); + assertTrue(arr1.getClass().isArray()); + + // We must check primitive arrays as they cannot be cast to Object[] + if (arr1 instanceof boolean[]) { + assertArrayEquals((boolean[]) arr1, (boolean[]) arr2); + } + else if (arr1 instanceof byte[]) { + assertArrayEquals((byte[]) arr1, (byte[]) arr2); + } + else if (arr1 instanceof short[]) { + assertArrayEquals((short[]) arr1, (short[]) arr2); + } + else if (arr1 instanceof int[]) { + assertArrayEquals((int[]) arr1, (int[]) arr2); + } + else if (arr1 instanceof long[]) { + assertArrayEquals((long[]) arr1, (long[]) arr2); + } + else if (arr1 instanceof float[]) { + assertArrayEquals((float[]) arr1, (float[]) arr2, 1e-6f); + } + else if (arr1 instanceof double[]) { + assertArrayEquals((double[]) arr1, (double[]) arr2, 1e-6); + } + else if (arr1 instanceof char[]) { + assertArrayEquals((char[]) arr1, (char[]) arr2); + } + // Otherwise we can just cast to Object[] + else assertArrayEquals((Object[]) arr1, (Object[]) arr2); + } + // -- Helper methods -- private Object[] createInputArray() { @@ -167,7 +233,7 @@ private Object[] createInputArray() { "integer1", -2, // "integer2", 7, // "double1", Math.E, // - "double2", Math.PI // + "double2", Math.PI, // }; } diff --git a/src/test/java/org/scijava/module/event/ModuleErroredEventTest.java b/src/test/java/org/scijava/module/event/ModuleErroredEventTest.java new file mode 100644 index 000000000..25bb195ba --- /dev/null +++ b/src/test/java/org/scijava/module/event/ModuleErroredEventTest.java @@ -0,0 +1,119 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.module.event; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertNotNull; + +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.event.EventHandler; +import org.scijava.event.EventService; +import org.scijava.module.AbstractModule; +import org.scijava.module.AbstractModuleInfo; +import org.scijava.module.Module; +import org.scijava.module.ModuleException; +import org.scijava.module.ModuleInfo; +import org.scijava.module.ModuleService; + +/** + * Tests {@link ModuleErroredEvent} behavior. + * + * @author Gabriel Selzer + * @author Curtis Rueden + */ +public class ModuleErroredEventTest { + + private EventService es; + private ModuleService module; + + @Before + public void setUp() { + Context ctx = new Context(); + es = ctx.getService(EventService.class); + module = ctx.getService(ModuleService.class); + } + + @Test + public void testModuleErroredEvent() { + + // Must be a final boolean array to be included in the below closure + final Throwable[] caughtException = { null }; + + // Add a new EventHandler to change our state + final Object interestedParty = new Object() { + + @EventHandler + void onEvent(final ModuleErroredEvent e) { + caughtException[0] = e.getException(); + e.consume(); // Prevent exception from being emitted to stderr. + } + }; + es.subscribe(interestedParty); + + // Run the module, ensure we get the exception + assertThrows(Exception.class, // + () -> module.run(new TestModuleInfo(), false).get()); + assertNotNull(caughtException[0]); + assertEquals("Yay!", caughtException[0].getMessage()); + } + + static class TestModuleInfo extends AbstractModuleInfo { + + @Override + public String getDelegateClassName() { + return this.getClass().getName(); + } + + @Override + public Class loadDelegateClass() throws ClassNotFoundException { + return this.getClass(); + } + + @Override + public Module createModule() throws ModuleException { + ModuleInfo thisInfo = this; + return new AbstractModule() { + + @Override + public ModuleInfo getInfo() { + return thisInfo; + } + + @Override + public void run() { + throw new RuntimeException("Yay!"); + } + }; + } + } +} diff --git a/src/test/java/org/scijava/module/process/LoggerPreprocessorTest.java b/src/test/java/org/scijava/module/process/LoggerPreprocessorTest.java index a0dd141ff..030413018 100644 --- a/src/test/java/org/scijava/module/process/LoggerPreprocessorTest.java +++ b/src/test/java/org/scijava/module/process/LoggerPreprocessorTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java b/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java index 3425c654b..62507cdc1 100644 --- a/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java +++ b/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/object/NamedObjectIndexTest.java b/src/test/java/org/scijava/object/NamedObjectIndexTest.java index ad5fd4aa7..15a995519 100644 --- a/src/test/java/org/scijava/object/NamedObjectIndexTest.java +++ b/src/test/java/org/scijava/object/NamedObjectIndexTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/object/ObjectIndexTest.java b/src/test/java/org/scijava/object/ObjectIndexTest.java index e81c87e1f..7bf973ea8 100644 --- a/src/test/java/org/scijava/object/ObjectIndexTest.java +++ b/src/test/java/org/scijava/object/ObjectIndexTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,6 +36,7 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -209,15 +210,27 @@ public void testToString() { objectIndex.add(new Integer(5)); objectIndex.add(new Float(2.5f)); objectIndex.add(new Integer(3)); - final String[] expected = - { "java.io.Serializable: {5, 2.5, 3}", - "java.lang.Comparable: {5, 2.5, 3}", "java.lang.Float: {2.5}", - "java.lang.Integer: {5, 3}", "java.lang.Number: {5, 2.5, 3}", - "java.lang.Object: {5, 2.5, 3}", - "org.scijava.object.ObjectIndex$All: {5, 2.5, 3}" }; + + final List expected = new ArrayList<>(); + expected.addAll(Arrays.asList( + "java.io.Serializable: {5, 2.5, 3}", + "java.lang.Comparable: {5, 2.5, 3}", + "java.lang.Float: {2.5}", + "java.lang.Integer: {5, 3}", + "java.lang.Number: {5, 2.5, 3}", + "java.lang.Object: {5, 2.5, 3}" + )); + final String[] javaVersion = System.getProperty("java.version").split("\\."); + final int majorVersion = Integer.parseInt(javaVersion[0]); + if (majorVersion >= 12) { + expected.add("java.lang.constant.Constable: {5, 2.5, 3}"); + expected.add("java.lang.constant.ConstantDesc: {5, 2.5, 3}"); + } + expected.add("org.scijava.object.ObjectIndex$All: {5, 2.5, 3}"); + final String[] actual = objectIndex.toString().split(System.getProperty("line.separator")); - assertArrayEquals(expected, actual); + assertArrayEquals(expected.toArray(), actual); } } diff --git a/src/test/java/org/scijava/object/ObjectServiceTest.java b/src/test/java/org/scijava/object/ObjectServiceTest.java index 321a402cb..871babfe1 100644 --- a/src/test/java/org/scijava/object/ObjectServiceTest.java +++ b/src/test/java/org/scijava/object/ObjectServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/object/SortedObjectIndexTest.java b/src/test/java/org/scijava/object/SortedObjectIndexTest.java index 61894ab78..7086dc505 100644 --- a/src/test/java/org/scijava/object/SortedObjectIndexTest.java +++ b/src/test/java/org/scijava/object/SortedObjectIndexTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/options/OptionsTest.java b/src/test/java/org/scijava/options/OptionsTest.java index 3ed1d5f08..8ca77769c 100644 --- a/src/test/java/org/scijava/options/OptionsTest.java +++ b/src/test/java/org/scijava/options/OptionsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -94,14 +94,14 @@ public void testPersistence() { assertEquals(0, fooOptions.getBar()); // verify that we can set bar to a desired value at all - fooOptions.setBar(0xcafebabe); - assertEquals(0xcafebabe, fooOptions.getBar()); + fooOptions.setBar(0xc0ffee); + assertEquals(0xc0ffee, fooOptions.getBar()); // verify that save and load work as expected in the same context fooOptions.save(); fooOptions.setBar(0xdeadbeef); fooOptions.load(); - assertEquals(0xcafebabe, fooOptions.getBar()); + assertEquals(0xc0ffee, fooOptions.getBar()); // throw away the 1st context optionsService.getContext().dispose(); @@ -112,7 +112,7 @@ public void testPersistence() { final FooOptions fooOptions = optionsService.getOptions(FooOptions.class); // verify that persisted values are loaded correctly in a new context - assertEquals(0xcafebabe, fooOptions.getBar()); + assertEquals(0xc0ffee, fooOptions.getBar()); // clean up for next time fooOptions.reset(); // FIXME: If this test fails, reset will not happen! diff --git a/src/test/java/org/scijava/parse/ParseServiceTest.java b/src/test/java/org/scijava/parse/ParseServiceTest.java index a5053766c..47d77939a 100644 --- a/src/test/java/org/scijava/parse/ParseServiceTest.java +++ b/src/test/java/org/scijava/parse/ParseServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/plugin/PluginFinderTest.java b/src/test/java/org/scijava/plugin/PluginFinderTest.java index 004165143..20fc70ce7 100644 --- a/src/test/java/org/scijava/plugin/PluginFinderTest.java +++ b/src/test/java/org/scijava/plugin/PluginFinderTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/plugin/PluginIndexTest.java b/src/test/java/org/scijava/plugin/PluginIndexTest.java index 485484287..f4727f067 100644 --- a/src/test/java/org/scijava/plugin/PluginIndexTest.java +++ b/src/test/java/org/scijava/plugin/PluginIndexTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/plugin/PluginInfoTest.java b/src/test/java/org/scijava/plugin/PluginInfoTest.java index c7e2fbea5..7df6a64d7 100644 --- a/src/test/java/org/scijava/plugin/PluginInfoTest.java +++ b/src/test/java/org/scijava/plugin/PluginInfoTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/plugin/SingletonServiceTest.java b/src/test/java/org/scijava/plugin/SingletonServiceTest.java index a4eabeec7..59d035333 100644 --- a/src/test/java/org/scijava/plugin/SingletonServiceTest.java +++ b/src/test/java/org/scijava/plugin/SingletonServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/prefs/PrefServiceTest.java b/src/test/java/org/scijava/prefs/PrefServiceTest.java index 1f2ee361a..d0635a962 100644 --- a/src/test/java/org/scijava/prefs/PrefServiceTest.java +++ b/src/test/java/org/scijava/prefs/PrefServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/run/RunServiceTest.java b/src/test/java/org/scijava/run/RunServiceTest.java index 5b0189b7b..16103455d 100644 --- a/src/test/java/org/scijava/run/RunServiceTest.java +++ b/src/test/java/org/scijava/run/RunServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/script/AbstractScriptLanguageTest.java b/src/test/java/org/scijava/script/AbstractScriptLanguageTest.java index 42d0a0707..731d9182a 100644 --- a/src/test/java/org/scijava/script/AbstractScriptLanguageTest.java +++ b/src/test/java/org/scijava/script/AbstractScriptLanguageTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/script/ScriptEngineTest.java b/src/test/java/org/scijava/script/ScriptEngineTest.java index 62914f64a..f8ad95821 100644 --- a/src/test/java/org/scijava/script/ScriptEngineTest.java +++ b/src/test/java/org/scijava/script/ScriptEngineTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/script/ScriptFinderTest.java b/src/test/java/org/scijava/script/ScriptFinderTest.java index 5c77988a6..04ca2d02d 100644 --- a/src/test/java/org/scijava/script/ScriptFinderTest.java +++ b/src/test/java/org/scijava/script/ScriptFinderTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -66,7 +66,7 @@ public class ScriptFinderTest { public static void setUp() throws IOException { scriptsDir = TestUtils.createTemporaryDirectory("script-finder-"); final String[] scriptPaths = { // - "ignored.foo", // + "script_in_base_dir.foo", // "Scripts/quick.foo", // "Scripts/brown.foo", // "Scripts/fox.foo", // @@ -108,6 +108,7 @@ public void testFindScripts() { "Math > multiply", // "Math > pow", // "Scripts > quick", // + "Plugins > Scripts > script in base dir", // "Math > Trig > sin", // "Math > subtract", // "Math > Trig > tan", // @@ -139,10 +140,10 @@ public void testMenuPrefixes() { "Foo > Bar > Math > Trig > cos", // "Foo > Bar > Math > divide", // "Foo > Bar > Scripts > fox", // - "Foo > Bar > ignored", // "Foo > Bar > Math > multiply", // "Math > pow", // "Foo > Bar > Scripts > quick", // + "Foo > Bar > script in base dir", // "Foo > Bar > Math > Trig > sin", // "Foo > Bar > Math > subtract", // "Foo > Bar > Math > Trig > tan", // @@ -177,6 +178,7 @@ public void testOverlappingDirectories() { "Math > multiply", // "Math > pow", // "Plugins > quick", // + "Plugins > Scripts > script in base dir", // "Math > Trig > sin", // "Math > subtract", // "Math > Trig > tan", // diff --git a/src/test/java/org/scijava/script/ScriptInfoTest.java b/src/test/java/org/scijava/script/ScriptInfoTest.java index 53691a948..a2cf4c375 100644 --- a/src/test/java/org/scijava/script/ScriptInfoTest.java +++ b/src/test/java/org/scijava/script/ScriptInfoTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,6 +31,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -337,6 +339,35 @@ public void testScriptDirective() { assertEquals("bar", info.get("foo")); } + /** Tests the {@code language} key of the {@code #@script} directive. */ + @Test + public void testScriptDirectiveLanguage() { + // Use a .txt extension so language is NOT auto-inferred from the path. + // Confirm it starts out null (no language for .txt). + final String scriptByName = "#@script(language=\"BindingSizes\")\nWOOT\n"; + final ScriptInfo infoByName = + new ScriptInfo(context, "test.txt", new StringReader(scriptByName)); + assertNull(infoByName.getLanguage()); // no language yet + infoByName.inputs(); // trigger parsing + assertNotNull(infoByName.getLanguage()); + assertTrue(infoByName.getLanguage().getNames().contains("BindingSizes")); + + // Also confirm lookup by file extension works. + final String scriptByExt = "#@script(language=\"bsizes\")\nWOOT\n"; + final ScriptInfo infoByExt = + new ScriptInfo(context, "test.txt", new StringReader(scriptByExt)); + infoByExt.inputs(); + assertNotNull(infoByExt.getLanguage()); + assertTrue(infoByExt.getLanguage().getExtensions().contains("bsizes")); + + // Unknown language name should leave language unset (null for .txt path). + final String scriptBogus = "#@script(language=\"no-such-language\")\nWOOT\n"; + final ScriptInfo infoBogus = + new ScriptInfo(context, "test.txt", new StringReader(scriptBogus)); + infoBogus.inputs(); + assertNull(infoBogus.getLanguage()); + } + /** * Ensures the ScriptInfos Reader can be reused for multiple executions of the * script. diff --git a/src/test/java/org/scijava/script/ScriptServiceTest.java b/src/test/java/org/scijava/script/ScriptServiceTest.java index f3dda2de3..6379c0fb0 100644 --- a/src/test/java/org/scijava/script/ScriptServiceTest.java +++ b/src/test/java/org/scijava/script/ScriptServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/script/process/ParameterScriptProcessorTest.java b/src/test/java/org/scijava/script/process/ParameterScriptProcessorTest.java index 3256d6062..df50fe820 100644 --- a/src/test/java/org/scijava/script/process/ParameterScriptProcessorTest.java +++ b/src/test/java/org/scijava/script/process/ParameterScriptProcessorTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/service/ServiceIndexTest.java b/src/test/java/org/scijava/service/ServiceIndexTest.java index af260c4ca..595c57581 100644 --- a/src/test/java/org/scijava/service/ServiceIndexTest.java +++ b/src/test/java/org/scijava/service/ServiceIndexTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/task/TaskEventTest.java b/src/test/java/org/scijava/task/TaskEventTest.java index fadecc683..542a8a52a 100644 --- a/src/test/java/org/scijava/task/TaskEventTest.java +++ b/src/test/java/org/scijava/task/TaskEventTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -72,7 +72,13 @@ public void testManyTasks() throws InterruptedException { for (int i=0;i getExtensions() { + return Arrays.asList("foo"); + } + + @Override + public String asHTML(final String text) { + return "[FOO]" + text + "[/FOO]"; + } + } +} diff --git a/src/test/java/org/scijava/thread/ThreadServiceTest.java b/src/test/java/org/scijava/thread/ThreadServiceTest.java index 0e92db904..569c15314 100644 --- a/src/test/java/org/scijava/thread/ThreadServiceTest.java +++ b/src/test/java/org/scijava/thread/ThreadServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/ui/UIServiceTest.java b/src/test/java/org/scijava/ui/UIServiceTest.java index 815b186d4..69a9ec6e7 100644 --- a/src/test/java/org/scijava/ui/UIServiceTest.java +++ b/src/test/java/org/scijava/ui/UIServiceTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,6 +31,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.List; @@ -79,19 +80,40 @@ public void testAvailableUIs() { @Test public void testHeadlessUI() { + // If true here, before we messed with it, the assumption is that we are + // in a truly headless environment, not just forced via setHeadless(true). + boolean reallyHeadless = uiService.isHeadless(); + final MockUserInterface mockUI = new MockUserInterface(); uiService.setDefaultUI(mockUI); // test non-headless behavior - uiService.setHeadless(false); - assertFalse(uiService.isHeadless()); - assertTrue(uiService.getDefaultUI() instanceof MockUserInterface); - - // test headless behavior - uiService.setHeadless(true); - assertTrue(uiService.isHeadless()); - assertTrue("UIService should return HeadlessUI when running \"headless\"", - uiService.getDefaultUI() instanceof HeadlessUI); + if (reallyHeadless) { + // This environment is truly headless, and + // we should not be able to override it. + uiService.setHeadless(false); + assertTrue(uiService.isHeadless()); + assertTrue("UIService should return HeadlessUI when running \"headless\"", + uiService.getDefaultUI() instanceof HeadlessUI); + } + else { + // This environment is not headless! We can test more things. + assertSame("UIService default UI override failed", + mockUI, uiService.getDefaultUI()); + + // This environment isn't headless now; + // let's test overriding it to be so. + uiService.setHeadless(true); + assertTrue(uiService.isHeadless()); + assertTrue("UIService should return HeadlessUI when running \"headless\"", + uiService.getDefaultUI() instanceof HeadlessUI); + + // Now we put it back! + uiService.setHeadless(false); + assertFalse(uiService.isHeadless()); + assertSame("UIService default UI override was not restored", + mockUI, uiService.getDefaultUI()); + } } private static final class MockUserInterface extends AbstractUserInterface { diff --git a/src/test/java/org/scijava/util/AppUtilsTest.java b/src/test/java/org/scijava/util/AppUtilsTest.java index ddf392bec..23412f0e7 100644 --- a/src/test/java/org/scijava/util/AppUtilsTest.java +++ b/src/test/java/org/scijava/util/AppUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/ArrayUtilsTest.java b/src/test/java/org/scijava/util/ArrayUtilsTest.java index c31e809a1..69a277f7a 100644 --- a/src/test/java/org/scijava/util/ArrayUtilsTest.java +++ b/src/test/java/org/scijava/util/ArrayUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/BoolArrayTest.java b/src/test/java/org/scijava/util/BoolArrayTest.java index 51c5f6b4c..952a6d2bc 100644 --- a/src/test/java/org/scijava/util/BoolArrayTest.java +++ b/src/test/java/org/scijava/util/BoolArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/ByteArrayTest.java b/src/test/java/org/scijava/util/ByteArrayTest.java index 31287b2a6..160124723 100644 --- a/src/test/java/org/scijava/util/ByteArrayTest.java +++ b/src/test/java/org/scijava/util/ByteArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/CharArrayTest.java b/src/test/java/org/scijava/util/CharArrayTest.java index 343a64b80..7fa1827fb 100644 --- a/src/test/java/org/scijava/util/CharArrayTest.java +++ b/src/test/java/org/scijava/util/CharArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/ClassUtilsTest.java b/src/test/java/org/scijava/util/ClassUtilsTest.java index 35e9c134e..25a673326 100644 --- a/src/test/java/org/scijava/util/ClassUtilsTest.java +++ b/src/test/java/org/scijava/util/ClassUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/ColorRGBTest.java b/src/test/java/org/scijava/util/ColorRGBTest.java index 4f3f68323..fea5f3d29 100644 --- a/src/test/java/org/scijava/util/ColorRGBTest.java +++ b/src/test/java/org/scijava/util/ColorRGBTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/ConversionUtilsTest.java b/src/test/java/org/scijava/util/ConversionUtilsTest.java index d04118628..5c63c2d03 100644 --- a/src/test/java/org/scijava/util/ConversionUtilsTest.java +++ b/src/test/java/org/scijava/util/ConversionUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,7 +43,6 @@ import java.util.Set; import org.junit.Test; -import org.scijava.util.Types; /** * Tests {@link ConversionUtils}. @@ -178,11 +177,14 @@ class Struct { assertEquals(123456789012.0, struct.myDoubles.get(0), 0.0); assertEquals(987654321098.0, struct.myDoubles.get(1), 0.0); - // Conversion to a list of strings (with no generic parameter) fails. + // Conversion to a list of strings (with no generic parameter) succeeds. setFieldValue(struct, "myStrings", longArray); - assertNull(struct.myStrings); + assertNotNull(struct.myStrings); + assertEquals(2, struct.myStrings.size()); + assertEquals("123456789012", struct.myStrings.get(0)); + assertEquals("987654321098", struct.myStrings.get(1)); } /** @@ -237,16 +239,15 @@ class Struct { /** * Tests setting an incompatible element value for a primitive array. */ - @Test(expected = IllegalArgumentException.class) public void testBadPrimitiveArray() { class Struct { - @SuppressWarnings("unused") private int[] intArray; } final Struct struct = new Struct(); setFieldValue(struct, "intArray", "not an int array"); + assertEquals(null, struct.intArray); } /** @@ -254,23 +255,46 @@ class Struct { * and a collection. */ @Test - public void testBadObjectElements() { + public void testIncompatibleCollections() { class Struct { - private Double[] doubleArray; - private List stringList; - @SuppressWarnings("unused") - private Set nestedArray; + private double[] primitiveDoubleArray; + private Double[] boxedDoubleArray; + private List numberList; + private Set setOfIntegerArrays; } final Struct struct = new Struct(); - // Test abnormal behavior for an object array - setFieldValue(struct, "doubleArray", "not a double array"); - assertEquals(null, struct.doubleArray[0]); - - // Test abnormal behavior for a list - setFieldValue(struct, "nestedArray", "definitely not a set of char arrays"); - assertNull(struct.stringList); + // NB: DefaultConverter converts non-collection/array objects to + // collection/array objects, even if some or all of the constituent elements + // cannot be converted to the array/collection component/element type. + + // Test object to incompatible primitive array type + setFieldValue(struct, "primitiveDoubleArray", "not a double array"); + assertNotNull(struct.primitiveDoubleArray); + assertEquals(1, struct.primitiveDoubleArray.length); + assertEquals(0.0, struct.primitiveDoubleArray[0], 0.0); + + // Test object to incompatible non-primitive array type + setFieldValue(struct, "boxedDoubleArray", "not a double array"); + assertNotNull(struct.boxedDoubleArray); + assertEquals(1, struct.boxedDoubleArray.length); + assertNull(struct.boxedDoubleArray[0]); + + // Test object to incompatible List type + setFieldValue(struct, "numberList", "not actually a list of numbers"); + List expectedList = Arrays.asList((Number) null); + assertEquals(expectedList, struct.numberList); + + // Test object to incompatible Set type + setFieldValue(struct, "setOfIntegerArrays", // + "definitely not a set of Integer[]"); + assertNotNull(struct.setOfIntegerArrays); + assertEquals(1, struct.setOfIntegerArrays.size()); + Integer[] singleton = struct.setOfIntegerArrays.iterator().next(); + assertNotNull(singleton); + assertEquals(1, singleton.length); + assertNull(singleton[0]); } /** diff --git a/src/test/java/org/scijava/util/DigestUtilsTest.java b/src/test/java/org/scijava/util/DigestUtilsTest.java index 657ee757d..c19510ab5 100644 --- a/src/test/java/org/scijava/util/DigestUtilsTest.java +++ b/src/test/java/org/scijava/util/DigestUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,11 +41,11 @@ */ public class DigestUtilsTest { - private static final byte[] CAFEBABE_SHA1 = { 20, 101, -38, -47, 38, -45, 43, - -9, -86, 93, 59, -107, -91, -57, -61, 49, -51, -1, 52, -33 }; + private static final byte[] COFFEE_SHA1 = { -71, 2, 27, -126, -23, -70, -89, + 35, -65, -15, -108, 66, 72, 113, 29, -32, -12, -42, -49, 6 }; - private static final byte[] CAFEBABE_MD5 = { 45, 27, -67, -30, -84, -84, 10, - -3, 7, 100, 109, -104, 21, 79, 64, 46 }; + private static final byte[] COFFEE_MD5 = { -39, -98, 9, -40, -39, 44, 31, + -62, 23, 9, 38, 101, 85, -57, 121, -110 }; private static final byte[] HELLO_WORLD_SHA1 = { 123, 80, 44, 58, 31, 72, -56, 96, -102, -30, 18, -51, -5, 99, -99, -18, 57, 103, 63, 94 }; @@ -53,14 +53,14 @@ public class DigestUtilsTest { private static final String HELLO_WORLD_SHA1_HEX = "7b502c3a1f48c8609ae212cdfb639dee39673f5e"; - private static final String CAFEBABE_SHA1_HEX = - "1465dad126d32bf7aa5d3b95a5c7c331cdff34df"; + private static final String COFFEE_SHA1_HEX = + "b9021b82e9baa723bff1944248711de0f4d6cf06"; private static final String HELLO_WORLD_SHA1_BASE64 = "e1AsOh9IyGCa4hLN+2Od7jlnP14="; - private static final String CAFEBABE_SHA1_BASE64 = - "FGXa0SbTK/eqXTuVpcfDMc3/NN8="; + private static final String COFFEE_SHA1_BASE64 = + "uQIbgum6pyO/8ZRCSHEd4PTWzwY="; /** Tests {@link DigestUtils#bytes(String)}. */ @Test @@ -75,15 +75,15 @@ public void testBytesString() { /** Tests {@link DigestUtils#bytes(int)}. */ @Test public void testBytesInt() { - final byte[] bytes = DigestUtils.bytes(0xcafebabe); - final byte[] expected = { -54, -2, -70, -66 }; + final byte[] bytes = DigestUtils.bytes(0xc0ffee); + final byte[] expected = { 0, -64, -1, -18 }; assertArrayEquals(expected, bytes); } /** Tests {@link DigestUtils#hex(byte[])}. */ @Test public void testHex() { - assertEquals("cafebabe", DigestUtils.hex(DigestUtils.bytes(0xcafebabe))); + assertEquals("00c0ffee", DigestUtils.hex(DigestUtils.bytes(0xc0ffee))); assertEquals("deadbeef", DigestUtils.hex(DigestUtils.bytes(0xdeadbeef))); assertEquals("00000000", DigestUtils.hex(DigestUtils.bytes(0x00000000))); assertEquals("ffffffff", DigestUtils.hex(DigestUtils.bytes(0xffffffff))); @@ -92,7 +92,7 @@ public void testHex() { /** Tests {@link DigestUtils#base64(byte[])}. */ @Test public void testBase64() { - assertEquals("yv66vg==", DigestUtils.base64(DigestUtils.bytes(0xcafebabe))); + assertEquals("AMD/7g==", DigestUtils.base64(DigestUtils.bytes(0xc0ffee))); assertEquals("3q2+7w==", DigestUtils.base64(DigestUtils.bytes(0xdeadbeef))); assertEquals("AAAAAA==", DigestUtils.base64(DigestUtils.bytes(0x00000000))); assertEquals("/////w==", DigestUtils.base64(DigestUtils.bytes(0xffffffff))); @@ -118,23 +118,23 @@ public void testHashBytes() { /** Tests {@link DigestUtils#sha1(byte[])}. */ @Test public void testSHA1() { - final byte[] bytes = DigestUtils.bytes(0xcafebabe); + final byte[] bytes = DigestUtils.bytes(0xc0ffee); final byte[] sha1 = DigestUtils.sha1(bytes); - assertArrayEquals(CAFEBABE_SHA1, sha1); + assertArrayEquals(COFFEE_SHA1, sha1); } /** Tests {@link DigestUtils#md5(byte[])}. */ @Test public void testMD5() { - final byte[] bytes = DigestUtils.bytes(0xcafebabe); + final byte[] bytes = DigestUtils.bytes(0xc0ffee); final byte[] md5 = DigestUtils.md5(bytes); - assertArrayEquals(CAFEBABE_MD5, md5); + assertArrayEquals(COFFEE_MD5, md5); } /** Tests {@link DigestUtils#digest(String, byte[])}. */ @Test public void testDigest() { - final byte[] bytes = DigestUtils.bytes(0xcafebabe); + final byte[] bytes = DigestUtils.bytes(0xc0ffee); final byte[] sha1 = DigestUtils.digest("SHA-1", bytes); final byte[] expectedSHA1 = DigestUtils.sha1(bytes); @@ -155,9 +155,9 @@ public void testBestString() { /** Tests {@link DigestUtils#best(byte[])}. */ @Test public void testBestBytes() { - final byte[] bytes = DigestUtils.bytes(0xcafebabe); + final byte[] bytes = DigestUtils.bytes(0xc0ffee); final byte[] best = DigestUtils.best(bytes); - assertArrayEquals(CAFEBABE_SHA1, best); + assertArrayEquals(COFFEE_SHA1, best); } /** Tests {@link DigestUtils#bestHex(String)}. */ @@ -169,8 +169,8 @@ public void testBestHexString() { /** Tests {@link DigestUtils#hex(byte[])}. */ @Test public void testBestHexBytes() { - final byte[] bytes = DigestUtils.bytes(0xcafebabe); - assertEquals(CAFEBABE_SHA1_HEX, DigestUtils.bestHex(bytes)); + final byte[] bytes = DigestUtils.bytes(0xc0ffee); + assertEquals(COFFEE_SHA1_HEX, DigestUtils.bestHex(bytes)); } /** Tests {@link DigestUtils#bestBase64(String)}. */ @@ -182,8 +182,8 @@ public void testBestBase64String() { /** Tests {@link DigestUtils#bestBase64(byte[])}. */ @Test public void testBestBase64Bytes() { - final byte[] bytes = DigestUtils.bytes(0xcafebabe); - assertEquals(CAFEBABE_SHA1_BASE64, DigestUtils.bestBase64(bytes)); + final byte[] bytes = DigestUtils.bytes(0xc0ffee); + assertEquals(COFFEE_SHA1_BASE64, DigestUtils.bestBase64(bytes)); } } diff --git a/src/test/java/org/scijava/util/DoubleArrayTest.java b/src/test/java/org/scijava/util/DoubleArrayTest.java index 093adb0a8..aeeaeb9ff 100644 --- a/src/test/java/org/scijava/util/DoubleArrayTest.java +++ b/src/test/java/org/scijava/util/DoubleArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/FileUtilsTest.java b/src/test/java/org/scijava/util/FileUtilsTest.java index dab013e7a..bbeb81232 100644 --- a/src/test/java/org/scijava/util/FileUtilsTest.java +++ b/src/test/java/org/scijava/util/FileUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -157,8 +157,8 @@ public void testShortenPath() { .shortenPath("\\\\server\\p1\\p2\\p3\\p4\\p5\\p6")); assertEquals("\\\\server\\p1\\p2\\p3", FileUtils .shortenPath("\\\\server\\p1\\p2\\p3")); - assertEquals("http://www.rgagnon.com/p1/p2/p3/.../pb.html", FileUtils - .shortenPath("http://www.rgagnon.com/p1/p2/p3/p4/p5/pb.html")); + assertEquals("https://www.rgagnon.com/p1/p2/p3/.../pb.html", FileUtils + .shortenPath("https://www.rgagnon.com/p1/p2/p3/p4/p5/pb.html")); } @Test @@ -177,8 +177,8 @@ public void testLimitPath() { "C:/1/2/3/4/5/test.txt", 15)); assertEquals("\\\\server\\p1\\p2\\...p6", FileUtils.limitPath( "\\\\server\\p1\\p2\\p3\\p4\\p5\\p6", 20)); - assertEquals("http://www...pb.html", FileUtils.limitPath( - "http://www.rgagnon.com/p1/p2/p3/p4/p5/pb.html", 20)); + assertEquals("https://www...pb.html", FileUtils.limitPath( + "https://www.rgagnon.com/p1/p2/p3/p4/p5/pb.html", 21)); } @Test diff --git a/src/test/java/org/scijava/util/FloatArrayTest.java b/src/test/java/org/scijava/util/FloatArrayTest.java index b5bc6801e..2f5274973 100644 --- a/src/test/java/org/scijava/util/FloatArrayTest.java +++ b/src/test/java/org/scijava/util/FloatArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/GenericArrayTypesTest.java b/src/test/java/org/scijava/util/GenericArrayTypesTest.java index 73e6046df..f153471e0 100644 --- a/src/test/java/org/scijava/util/GenericArrayTypesTest.java +++ b/src/test/java/org/scijava/util/GenericArrayTypesTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/IntArrayTest.java b/src/test/java/org/scijava/util/IntArrayTest.java index 33b515224..7e0f8f42a 100644 --- a/src/test/java/org/scijava/util/IntArrayTest.java +++ b/src/test/java/org/scijava/util/IntArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/LastRecentlyUsedTest.java b/src/test/java/org/scijava/util/LastRecentlyUsedTest.java index 2d17082ba..5cac06fea 100644 --- a/src/test/java/org/scijava/util/LastRecentlyUsedTest.java +++ b/src/test/java/org/scijava/util/LastRecentlyUsedTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/LongArrayTest.java b/src/test/java/org/scijava/util/LongArrayTest.java index 81f41c692..1452fa43c 100644 --- a/src/test/java/org/scijava/util/LongArrayTest.java +++ b/src/test/java/org/scijava/util/LongArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/NumberUtilsTest.java b/src/test/java/org/scijava/util/NumberUtilsTest.java new file mode 100644 index 000000000..67c9f3743 --- /dev/null +++ b/src/test/java/org/scijava/util/NumberUtilsTest.java @@ -0,0 +1,70 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.util; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Tests {@link NumberUtils} functionality + * + * @author Gabriel Selzer + */ +public class NumberUtilsTest { + + /** Tests {@link NumberUtils#getMinimumNumber(Class)} */ + @Test + public void testGetMinimumNumber() { + assertEquals(Byte.MIN_VALUE, NumberUtils.getMinimumNumber(Byte.class)); + assertEquals(Short.MIN_VALUE, NumberUtils.getMinimumNumber(Short.class)); + assertEquals(Integer.MIN_VALUE, NumberUtils.getMinimumNumber( + Integer.class)); + assertEquals(Long.MIN_VALUE, NumberUtils.getMinimumNumber(Long.class)); + assertEquals(-Float.MAX_VALUE, NumberUtils.getMinimumNumber(Float.class)); + assertEquals(-Double.MAX_VALUE, NumberUtils.getMinimumNumber(Double.class)); + // Number's minimum value should be the smallest of all the above -> Double + assertEquals(-Double.MAX_VALUE, NumberUtils.getMinimumNumber(Number.class)); + } + + /** Tests {@link NumberUtils#getMaximumNumber(Class)} */ + @Test + public void testGetMaximumNumber() { + assertEquals(Byte.MAX_VALUE, NumberUtils.getMaximumNumber(Byte.class)); + assertEquals(Short.MAX_VALUE, NumberUtils.getMaximumNumber(Short.class)); + assertEquals(Integer.MAX_VALUE, NumberUtils.getMaximumNumber( + Integer.class)); + assertEquals(Long.MAX_VALUE, NumberUtils.getMaximumNumber(Long.class)); + assertEquals(Float.MAX_VALUE, NumberUtils.getMaximumNumber(Float.class)); + assertEquals(Double.MAX_VALUE, NumberUtils.getMaximumNumber(Double.class)); + // Number's maximum value should be the largest of all the above -> Double + assertEquals(Double.MAX_VALUE, NumberUtils.getMaximumNumber(Number.class)); + } +} diff --git a/src/test/java/org/scijava/util/ObjectArrayTest.java b/src/test/java/org/scijava/util/ObjectArrayTest.java index bb654fa0f..0e9a94f4c 100644 --- a/src/test/java/org/scijava/util/ObjectArrayTest.java +++ b/src/test/java/org/scijava/util/ObjectArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/POMTest.java b/src/test/java/org/scijava/util/POMTest.java index dad7a7aa7..7ac2f0eef 100644 --- a/src/test/java/org/scijava/util/POMTest.java +++ b/src/test/java/org/scijava/util/POMTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/PrimitiveArrayTest.java b/src/test/java/org/scijava/util/PrimitiveArrayTest.java index 747b0fdac..5612174d0 100644 --- a/src/test/java/org/scijava/util/PrimitiveArrayTest.java +++ b/src/test/java/org/scijava/util/PrimitiveArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/ProcessUtilsTest.java b/src/test/java/org/scijava/util/ProcessUtilsTest.java index 2b717cb92..056ffac37 100644 --- a/src/test/java/org/scijava/util/ProcessUtilsTest.java +++ b/src/test/java/org/scijava/util/ProcessUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/PropertiesHelperTest.java b/src/test/java/org/scijava/util/PropertiesHelperTest.java new file mode 100644 index 000000000..528dc25dc --- /dev/null +++ b/src/test/java/org/scijava/util/PropertiesHelperTest.java @@ -0,0 +1,138 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2026 SciJava developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ + +package org.scijava.util; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Tests for {@link PropertiesHelper} + */ +public class PropertiesHelperTest { + + private static final String EXPECTED_1 = "a=b"; + private static final String EXPECTED_2 = "hello=goodbye"; + + private Map props; + private File temp; + + @Before + public void setup() throws IOException { + temp = File.createTempFile("PropertiesHelper", "txt"); + props = new HashMap<>(); + props.put("a", "b"); + props.put("hello", "goodbye"); + } + + @After + public void cleanup() { + temp.delete(); + } + + @Test + public void testWrite() throws IOException { + PropertiesHelper.put(props, temp); + + int count = 0; + boolean saw1 = false, saw2 = false; + + try (BufferedReader reader = new BufferedReader(new FileReader(temp))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.equals(EXPECTED_1)) { + saw1 = true; + } + if (line.equals(EXPECTED_2)) { + saw2 = true; + } + count++; + } + } + assertTrue(saw1); + assertTrue(saw2); + assertEquals(2, count); + } + + @Test + public void testRead() throws IOException { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(temp))) { + writer.write(EXPECTED_1); + writer.newLine(); + writer.write(EXPECTED_2); + writer.newLine(); + } + + Map propsMap = PropertiesHelper.get(temp); + assertTrue(props.equals(propsMap)); + } + + @Test + public void testIO() throws IOException { + PropertiesHelper.put(props, temp); + Map propsMap = PropertiesHelper.get(temp); + assertTrue(props.equals(propsMap)); + } + + @Test + public void testMultipleEquals() throws IOException { + props.clear(); + final String K = "hello", V = "world=true"; + props.put(K, V); + PropertiesHelper.put(props, temp); + Map propsMap = PropertiesHelper.get(temp); + assertEquals(1, propsMap.size()); + assertEquals(props.get(K), propsMap.get(K)); + } + + @Test + public void testOverwrite() throws IOException { + PropertiesHelper.put(props, temp); + props.put("myname", "jonas"); + PropertiesHelper.put(props, temp); + Map loadedProps = PropertiesHelper.get(temp); + assertEquals(3, loadedProps.size()); + int count = 0; + try (BufferedReader reader = new BufferedReader(new FileReader(temp))) { + String line; + while ((line = reader.readLine()) != null) { + count++; + } + } + assertEquals(3, count); + } +} diff --git a/src/test/java/org/scijava/util/ShortArrayTest.java b/src/test/java/org/scijava/util/ShortArrayTest.java index e4d3f7ed6..24adec352 100644 --- a/src/test/java/org/scijava/util/ShortArrayTest.java +++ b/src/test/java/org/scijava/util/ShortArrayTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/StringUtilsTest.java b/src/test/java/org/scijava/util/StringUtilsTest.java index 4fac7e5e7..a04bc3236 100644 --- a/src/test/java/org/scijava/util/StringUtilsTest.java +++ b/src/test/java/org/scijava/util/StringUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/TypesTest.java b/src/test/java/org/scijava/util/TypesTest.java index 21fce520d..1eb1707a5 100644 --- a/src/test/java/org/scijava/util/TypesTest.java +++ b/src/test/java/org/scijava/util/TypesTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -593,7 +593,7 @@ public void testEnumValue() { /** Tests {@link Types#enumValue(String, Class)} for invalid value. */ @Test(expected = IllegalArgumentException.class) public void testEnumValueNoConstant() { - Types.enumValue("NONE", Words.class); + Types.enumValue("OMG", Words.class); } /** Tests {@link Types#enumValue(String, Class)} for non-enum class. */ @@ -602,6 +602,38 @@ public void testEnumValueNonEnum() { Types.enumValue("HOOYAH", String.class); } + /** Tests {@link Types#enumFromLabel(String, Class)}. */ + @Test + public void testEnumFromLabel() { + final Words foo = Types.enumFromLabel("Foo", Words.class); + assertSame(Words.FOO, foo); + final Words bar = Types.enumFromLabel("Bar", Words.class); + assertSame(Words.BAR, bar); + final Words fubar = Types.enumFromLabel("OMG", Words.class); + assertSame(Words.FUBAR, fubar); + } + + /** Tests {@link Types#enumFromString(String, Class)}. */ + @Test + public void testEnumFromString() { + { + final Words foo = Types.enumFromString("FOO", Words.class); + assertSame(Words.FOO, foo); + final Words bar = Types.enumFromString("BAR", Words.class); + assertSame(Words.BAR, bar); + final Words fubar = Types.enumFromString("FUBAR", Words.class); + assertSame(Words.FUBAR, fubar); + } + { + final Words foo = Types.enumFromString("Foo", Words.class); + assertSame(Words.FOO, foo); + final Words bar = Types.enumFromString("Bar", Words.class); + assertSame(Words.BAR, bar); + final Words fubar = Types.enumFromString("OMG", Words.class); + assertSame(Words.FUBAR, fubar); + } + } + /** Tests {@link Types#parameterize(Class, Map)}. */ @Test public void testParameterizeMap() { @@ -644,7 +676,18 @@ private static class ComplexThing extends /** Enumeration for testing conversion to enum types. */ public static enum Words { - FOO, BAR, FUBAR + FOO("Foo"), BAR("Bar"), FUBAR("OMG"); + + private final String label; + + private Words(final String label) { + this.label = label; + } + + @Override + public String toString() { + return label; + } } private interface TestTypes { diff --git a/src/test/java/org/scijava/util/UnitUtilsTest.java b/src/test/java/org/scijava/util/UnitUtilsTest.java index e095f60a0..7977d0a7b 100644 --- a/src/test/java/org/scijava/util/UnitUtilsTest.java +++ b/src/test/java/org/scijava/util/UnitUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/util/VersionUtilsTest.java b/src/test/java/org/scijava/util/VersionUtilsTest.java index 7b0844225..de09b9888 100644 --- a/src/test/java/org/scijava/util/VersionUtilsTest.java +++ b/src/test/java/org/scijava/util/VersionUtilsTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/test/java/org/scijava/widget/WidgetStyleTest.java b/src/test/java/org/scijava/widget/WidgetStyleTest.java index 321342736..dbe4f8c83 100644 --- a/src/test/java/org/scijava/widget/WidgetStyleTest.java +++ b/src/test/java/org/scijava/widget/WidgetStyleTest.java @@ -2,7 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2022 SciJava developers. + * Copyright (C) 2009 - 2026 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: