diff --git a/.github/build.sh b/.github/build.sh new file mode 100755 index 000000000..523abeb87 --- /dev/null +++ b/.github/build.sh @@ -0,0 +1,3 @@ +#!/bin/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 new file mode 100755 index 000000000..0ebca586f --- /dev/null +++ b/.github/setup.sh @@ -0,0 +1,10 @@ +#!/bin/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.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..a57c0df0b --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,42 @@ +name: build + +on: + push: + branches: + - master + tags: + - "*-[0-9]+.*" + pull_request: + branches: + - master + +jobs: + build: + name: build-${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v4 + - name: Set up Java + 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 }} + CENTRAL_USER: ${{ secrets.CENTRAL_USER }} + CENTRAL_PASS: ${{ secrets.CENTRAL_PASS }} + SIGNING_ASC: ${{ secrets.SIGNING_ASC }} diff --git a/.mailmap b/.mailmap index e5a0e733c..5157cbbe1 100644 --- a/.mailmap +++ b/.mailmap @@ -1,7 +1,16 @@ Barry DeZonia -Christian Dietz +Christian Dietz +Christian Dietz +Gabriel Einsdorf +Gabriel Einsdorf +Gabriel Selzer +Gabriel Selzer ImageJ Jenkins +Jan Eglinger Johannes Schindelin Johannes Schindelin Jonathan Hale +Leon Yang +Leon Yang Mark Hiner +Richard Domander diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b3fcda211..000000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: java -jdk: oraclejdk8 -branches: - only: - - master - - "/.*-[0-9]+\\..*/" -install: true -script: ".travis/build.sh" -cache: - directories: - - "~/.m2/repository" -env: - global: - - secure: Xkwu2u/v0+kBqW2Mt80FpMS+2NRMnfRaZ6ptiEW44sViKkaENnJegmYVjdSm9RAwAJx9DEp6KYTLH4Hh56JbWp6s8qGcxm2vCbAWBE6ZesOj3oTvv/T4lucxarocZ8hK9NqfY9iCePjl8R10UDePThZgWBFidUQjvPbH+LcXo9g= - - secure: Jgj204N4hKv+7sUrXGtXMvUoXYuHAerhUvwbHsm0BJFpzUSyHP5QWJH2tHvCUL9Yb4VhNEjc46RLFVmiIXynJwAdAWJodT/VEnOTb5Cf7+0UHK4qCyjyjVHiWq1cf+R8Lr9fuKRqxUAdz9Hw6g0Yt23TX8kCa+wQW9lwchn0IG8= - - secure: RuGzuPrxyvBRJwsCpSJ10p9PdP2Hzc9lxb29L//Y/Fkc3bJwNMlNa0ST83oGNHJapYc4dWuFk22Ooy/2YioNgsVvR4n5MAslqXQXSY0VDle1Nbf1pudAlPU+quaiYxcAyyysjUUtqc5wADVgpkrDA7GJzAuCOWb4aSwiiIn6u4A= - - secure: bnsjVlj9MBJto8ahZdMwGpVPjZeyF7r5tZh+t+NhDuZsP0WMlURzGZ9/lJOO4quklgiWCyeVDB5uvDvsdG9BReBe5Q8Q6WZyxhxYtP2iLV0zRWSWsGKk0stGcrmJKk8wbicIJdXD8suiP+2Li5GfxTge/hkhL4CL0OOr6b1JqrM= diff --git a/.travis/build.sh b/.travis/build.sh deleted file mode 100755 index 094a570ee..000000000 --- a/.travis/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -curl -fsLO https://raw.githubusercontent.com/scijava/scijava-scripts/master/travis-build.sh -sh travis-build.sh $encrypted_d2fbfc37eea9_key $encrypted_d2fbfc37eea9_iv diff --git a/.travis/signingkey.asc.enc b/.travis/signingkey.asc.enc deleted file mode 100644 index 4e4802b46..000000000 Binary files a/.travis/signingkey.asc.enc and /dev/null differ diff --git a/LICENSE.txt b/LICENSE.txt index 82d98ebc1..142f26652 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,4 @@ -Copyright (c) 2009 - 2017, Board of Regents of the University of -Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck -Institute of Molecular Cell Biology and Genetics, University of -Konstanz, and KNIME GmbH. +Copyright (c) 2009 - 2025, 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 0838f7b7b..ba1f15173 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -[![](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://travis-ci.org/scijava/scijava-common.svg?branch=master)](https://travis-ci.org/scijava/scijava-common) -[![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 by its own annotation processor, so that plugins can be loaded dynamically. -It is used by both [ImageJ](https://github.com/imagej/imagej) and +It is used by both [ImageJ2](https://github.com/imagej/imagej2) and [SCIFIO](https://github.com/scifio/scifio). diff --git a/pom.xml b/pom.xml index 2a76b2e4f..59020e2a3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,16 +1,16 @@ - + 4.0.0 org.scijava pom-scijava - 19.2.0 + 43.0.0 scijava-common - 2.74.3-SNAPSHOT + 2.99.4-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. @@ -18,7 +18,7 @@ 2009 SciJava - http://www.scijava.org/ + https://scijava.org/ @@ -31,7 +31,7 @@ ctrueden Curtis Rueden - http://imagej.net/User:Rueden + https://imagej.net/people/ctrueden founder lead @@ -46,86 +46,99 @@ Mark Hiner - http://imagej.net/User:Hinerm + https://imagej.net/people/hinerm founder hinerm Johannes Schindelin - http://imagej.net/User:Schindelin + https://imagej.net/people/dscho dscho Chris Allan chris-allan + + Nicolas Chiaruttini + https://imagej.net/people/NicoKiaru + NicoKiaru + Barry DeZonia - http://imagej.net/User:Bdezonia + https://imagej.net/people/bdezonia bdezonia Christian Dietz - http://imagej.net/User:Dietzc + https://imagej.net/people/dietzc dietzc Richard Domander - http://imagej.net/User:Rdom + https://imagej.net/people/rimadoma rimadoma Gabriel Einsdorf - http://imagej.net/User:Gab1one + https://imagej.net/people/gab1one gab1one Aivar Grislis - http://imagej.net/User:Grislis + https://imagej.net/people/grislis grislis Jonathan Hale + https://imagej.net/people/Squareys Squareys Grant Harris - http://imagej.net/User:Harris + https://imagej.net/people/tnargsirrah tnargsirrah Lee Kamentsky - http://imagej.net/User:Leek + https://imagej.net/people/LeeKamentsky LeeKamentsky Rick Lentz - http://imagej.net/User:Lentz + https://imagej.net/people/ricklentz + ricklentz Melissa Linkert - http://imagej.net/User:Linkert + https://imagej.net/people/melissalinkert melissalinkert Kevin Mader - http://imagej.net/User:Ksmader + https://imagej.net/people/kmader kmader Hadrien Mary - http://imagej.net/User:Hadim + https://imagej.net/people/hadim hadim Alison Walter - http://imagej.net/User:Awalter2 + https://imagej.net/people/awalter17 awalter17 Jay Warrick + https://imagej.net/people/jaywarrick jaywarrick + + Christian Tischer + https://imagej.net/people/tischi + tischi + @@ -139,7 +152,7 @@ - scm:git:git://github.com/scijava/scijava-common + scm:git:https://github.com/scijava/scijava-common scm:git:git@github.com:scijava/scijava-common HEAD https://github.com/scijava/scijava-common @@ -149,8 +162,8 @@ https://github.com/scijava/scijava-common/issues - Travis CI - https://travis-ci.org/scijava/scijava-common + GitHub Actions + https://github.com/scijava/scijava-common/actions @@ -158,10 +171,11 @@ bsd_2 SciJava Common shared library for SciJava software. - Board of Regents of the University of -Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck -Institute of Molecular Cell Biology and Genetics, University of -Konstanz, and KNIME GmbH. + SciJava developers. + **/bushe/** + + + 2.22.2 @@ -171,13 +185,6 @@ Konstanz, and KNIME GmbH. parsington - - - org.bushe - eventbus - 1.4 - - junit @@ -188,22 +195,22 @@ Konstanz, and KNIME GmbH. org.mockito mockito-core test - + - + org.apache.maven.plugins maven-compiler-plugin diff --git a/src/it/apt-test/pom.xml b/src/it/apt-test/pom.xml index 1647ef3ed..12f8b4d0a 100644 --- a/src/it/apt-test/pom.xml +++ b/src/it/apt-test/pom.xml @@ -3,10 +3,7 @@ #%L SciJava Common shared library for SciJava software. %% - Copyright (C) 2009 - 2017 Board of Regents of the University of - Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - Institute of Molecular Cell Biology and Genetics, University of - Konstanz, and KNIME GmbH. + Copyright (C) 2009 - 2025 SciJava developers. %% Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -34,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 563bf2b67..2f053786a 100644 --- a/src/it/apt-test/setup.bsh +++ b/src/it/apt-test/setup.bsh @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 aeb8b9cd5..5301e1794 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,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 1ef8c4510..4643aa288 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,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 84696a531..bc6a12a90 100644 --- a/src/it/apt-test/verify.bsh +++ b/src/it/apt-test/verify.bsh @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 f7dc233e8..02cd6280f 100644 --- a/src/it/settings.xml +++ b/src/it/settings.xml @@ -3,10 +3,7 @@ #%L SciJava Common shared library for SciJava software. %% - Copyright (C) 2009 - 2017 Board of Regents of the University of - Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - Institute of Molecular Cell Biology and Genetics, University of - Konstanz, and KNIME GmbH. + Copyright (C) 2009 - 2025 SciJava developers. %% Redistribution and use in source 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 a956f0b48..f05f40249 100644 --- a/src/main/java/org/scijava/AbstractBasicDetails.java +++ b/src/main/java/org/scijava/AbstractBasicDetails.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d11fb2c6f..0c76ae641 100644 --- a/src/main/java/org/scijava/AbstractContextual.java +++ b/src/main/java/org/scijava/AbstractContextual.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4f8362194..944c2dff0 100644 --- a/src/main/java/org/scijava/AbstractGateway.java +++ b/src/main/java/org/scijava/AbstractGateway.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -45,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; @@ -54,6 +52,7 @@ import org.scijava.platform.AppEventService; import org.scijava.platform.PlatformService; import org.scijava.plugin.AbstractRichPlugin; +import org.scijava.plugin.PluginInfo; import org.scijava.plugin.PluginService; import org.scijava.prefs.PrefService; import org.scijava.script.ScriptService; @@ -86,7 +85,15 @@ public AbstractGateway() { public AbstractGateway(final String appName, final Context context) { this.appName = appName; - if (context != null) setContext(context); + if (context != null) { + setContext(context); + + // NB: Make a best effort to inject plugin metadata. + final PluginInfo info = PluginInfo.getOrCreate(getClass(), + Gateway.class, context.getPluginIndex()); + info.inject(this); + Priority.inject(this, info.getPriority()); + } } // -- Gateway methods -- @@ -114,6 +121,8 @@ public void launch(final String... args) { @Override public String getShortName() { + final String pluginName = getInfo() == null ? null : getInfo().getName(); + if (pluginName != null && !pluginName.isEmpty()) return pluginName; return getClass().getSimpleName().toLowerCase(); } @@ -182,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 6627efa85..3590c19e3 100644 --- a/src/main/java/org/scijava/AbstractUIDetails.java +++ b/src/main/java/org/scijava/AbstractUIDetails.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 98884ff15..d2288061b 100644 --- a/src/main/java/org/scijava/BasicDetails.java +++ b/src/main/java/org/scijava/BasicDetails.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 fd8aae923..0c36b0066 100644 --- a/src/main/java/org/scijava/Cancelable.java +++ b/src/main/java/org/scijava/Cancelable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c3b928c2d..50014ad17 100644 --- a/src/main/java/org/scijava/Context.java +++ b/src/main/java/org/scijava/Context.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,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; @@ -61,7 +62,7 @@ * @author Curtis Rueden * @see Service */ -public class Context implements Disposable { +public class Context implements Disposable, AutoCloseable { // -- Constants -- @@ -75,6 +76,14 @@ public class Context implements Disposable { */ 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. */ @@ -100,6 +109,12 @@ public class Context implements Disposable { */ 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. * @@ -251,6 +266,13 @@ public Context(final Collection> serviceClasses, * those of lower priority). See {@link ServiceHelper#loadServices()} for more * information. *

+ *

+ * NB: Instiantiation of a Context has an implied requirement of a + * corresponding call to {@link Context#dispose()} at the end of the SciJava + * applicaton's lifecycle. This cleans up any remaining resources and allows + * the JVM to exit gracefully. This is called automatically when constructed as + * an {@link AutoCloseable}. + *

* * @param serviceClasses A collection of types that implement the * {@link Service} interface (e.g., {@code DisplayService.class}). @@ -280,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 -- @@ -414,16 +456,14 @@ public boolean isInjectable(final Class type) { @Override public void dispose() { - final EventService eventService = getService(EventService.class); - if (eventService != null) eventService.publish(new ContextDisposingEvent()); + doDispose(true); + } - // 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(); - } + // -- AutoCloseable methods -- + + @Override + public void close() { + dispose(); } // -- Utility methods -- @@ -440,6 +480,19 @@ public static List> serviceClassList( Arrays.asList(serviceClasses) : Arrays.asList(Service.class); } + /** + * Gets the class loader to use. This will be the current thread's context + * class loader if non-null; otherwise it will be the system class loader. + * + * @see Thread#getContextClassLoader() + * @see ClassLoader#getSystemClassLoader() + */ + public static ClassLoader getClassLoader() { + final ClassLoader contextCL = Thread.currentThread() + .getContextClassLoader(); + return contextCL != null ? contextCL : ClassLoader.getSystemClassLoader(); + } + // -- Helper methods -- private List getParameterFields(final Object o) { @@ -530,8 +583,7 @@ private String createMissingServiceMessage( final Class serviceType) { final String nl = System.getProperty("line.separator"); - final ClassLoader classLoader = // - Thread.currentThread().getContextClassLoader(); + final ClassLoader classLoader = getClassLoader(); final StringBuilder msg = new StringBuilder( "Required service is missing: " + serviceType.getName() + nl); msg.append("Context: " + this + nl); @@ -557,17 +609,34 @@ 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; } private static List> services(final boolean empty) { - if (empty) return Collections.>emptyList(); - return Arrays.>asList(Service.class); + if (empty) return Collections.> emptyList(); + return Arrays.> asList(Service.class); } private static boolean strict() { return !"false".equals(System.getProperty(STRICT_PROPERTY)); } - } diff --git a/src/main/java/org/scijava/Contextual.java b/src/main/java/org/scijava/Contextual.java index 682abfefe..4d83ca900 100644 --- a/src/main/java/org/scijava/Contextual.java +++ b/src/main/java/org/scijava/Contextual.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 9ec7aeec2..f3ac3548b 100644 --- a/src/main/java/org/scijava/Disposable.java +++ b/src/main/java/org/scijava/Disposable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 37a5b6403..9222f058c 100644 --- a/src/main/java/org/scijava/Gateway.java +++ b/src/main/java/org/scijava/Gateway.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,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; @@ -120,7 +118,7 @@ * @author Mark Hiner * @author Curtis Rueden */ -public interface Gateway extends RichPlugin { +public interface Gateway extends RichPlugin, Disposable { /** * Perform launch operations associated with this gateway. @@ -241,6 +239,13 @@ public interface Gateway extends RichPlugin { */ 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}. * @@ -372,4 +377,8 @@ public interface Gateway extends RichPlugin { /** @see org.scijava.app.App#getInfo(boolean) */ String getInfo(boolean mem); + @Override + default void dispose() { + context().dispose(); + } } diff --git a/src/main/java/org/scijava/Identifiable.java b/src/main/java/org/scijava/Identifiable.java index 0d88f23a4..a1be1c4e7 100644 --- a/src/main/java/org/scijava/Identifiable.java +++ b/src/main/java/org/scijava/Identifiable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c29b5fb0b..bd7de998f 100644 --- a/src/main/java/org/scijava/Initializable.java +++ b/src/main/java/org/scijava/Initializable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d67cf1298..7f1d82077 100644 --- a/src/main/java/org/scijava/Instantiable.java +++ b/src/main/java/org/scijava/Instantiable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7b1f55900..e2df38650 100644 --- a/src/main/java/org/scijava/InstantiableException.java +++ b/src/main/java/org/scijava/InstantiableException.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 febcc8629..c4198b74b 100644 --- a/src/main/java/org/scijava/ItemIO.java +++ b/src/main/java/org/scijava/ItemIO.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 da4e594d4..47b0e9276 100644 --- a/src/main/java/org/scijava/ItemVisibility.java +++ b/src/main/java/org/scijava/ItemVisibility.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c9b0e7039..5184b2552 100644 --- a/src/main/java/org/scijava/Locatable.java +++ b/src/main/java/org/scijava/Locatable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e29db087b..d436963fc 100644 --- a/src/main/java/org/scijava/MenuEntry.java +++ b/src/main/java/org/scijava/MenuEntry.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 26b732e17..941c4a860 100644 --- a/src/main/java/org/scijava/MenuPath.java +++ b/src/main/java/org/scijava/MenuPath.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f97542944..bdb669e16 100644 --- a/src/main/java/org/scijava/Named.java +++ b/src/main/java/org/scijava/Named.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 bf2bc79f6..4f25b47d3 100644 --- a/src/main/java/org/scijava/NoSuchServiceException.java +++ b/src/main/java/org/scijava/NoSuchServiceException.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c0509c937..32eca3f18 100644 --- a/src/main/java/org/scijava/NullContextException.java +++ b/src/main/java/org/scijava/NullContextException.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c96fc8892..34b10025a 100644 --- a/src/main/java/org/scijava/Optional.java +++ b/src/main/java/org/scijava/Optional.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 13f6f600c..8ecc6c528 100644 --- a/src/main/java/org/scijava/Prioritized.java +++ b/src/main/java/org/scijava/Prioritized.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 628904e36..e2fbddfd0 100644 --- a/src/main/java/org/scijava/Priority.java +++ b/src/main/java/org/scijava/Priority.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ebf387171..90a3be54c 100644 --- a/src/main/java/org/scijava/SciJava.java +++ b/src/main/java/org/scijava/SciJava.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -45,7 +42,7 @@ * * @author Curtis Rueden */ -@Plugin(type = Gateway.class) +@Plugin(type = Gateway.class, name = "sj") public class SciJava extends AbstractGateway { // -- Constructors -- @@ -113,12 +110,4 @@ public SciJava(final Collection> serviceClasses) { public SciJava(final Context context) { super(SciJavaApp.NAME, context); } - - // -- Gateway methods -- - - @Override - public String getShortName() { - return "sj"; - } - } diff --git a/src/main/java/org/scijava/Typed.java b/src/main/java/org/scijava/Typed.java index a5e28f0df..552d1fd00 100644 --- a/src/main/java/org/scijava/Typed.java +++ b/src/main/java/org/scijava/Typed.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 998742226..896c6bb18 100644 --- a/src/main/java/org/scijava/UIDetails.java +++ b/src/main/java/org/scijava/UIDetails.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 efa4acf93..4fabe278a 100644 --- a/src/main/java/org/scijava/Validated.java +++ b/src/main/java/org/scijava/Validated.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 10e8bf159..b95d1e02b 100644 --- a/src/main/java/org/scijava/ValidityProblem.java +++ b/src/main/java/org/scijava/ValidityProblem.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 36aabaea6..eb5c0cda5 100644 --- a/src/main/java/org/scijava/Versioned.java +++ b/src/main/java/org/scijava/Versioned.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c87d1da55..730739ca6 100644 --- a/src/main/java/org/scijava/annotations/AbstractIndexWriter.java +++ b/src/main/java/org/scijava/annotations/AbstractIndexWriter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4d399d8ea..33338727a 100644 --- a/src/main/java/org/scijava/annotations/AnnotationCombiner.java +++ b/src/main/java/org/scijava/annotations/AnnotationCombiner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,6 +40,7 @@ import java.util.HashSet; import java.util.Set; +import org.scijava.Context; import org.scijava.util.Combiner; import org.scijava.util.FileUtils; @@ -65,7 +63,7 @@ public void combine(File outputDirectory) throws Exception { } final Set annotationFiles = getAnnotationFiles(); - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final ClassLoader loader = Context.getClassLoader(); log(""); log("Writing annotations to " + outputDirectory.getAbsolutePath()); @@ -92,7 +90,7 @@ public Set getAnnotationFiles() throws IOException { for (final String prefix : new String[] { PREFIX, LEGACY_PREFIX }) { final Enumeration directories = - Thread.currentThread().getContextClassLoader().getResources(prefix); + Context.getClassLoader().getResources(prefix); while (directories.hasMoreElements()) { final URL url = directories.nextElement(); for (final URL annotationIndexURL : FileUtils.listContents(url)) { diff --git a/src/main/java/org/scijava/annotations/AnnotationProcessor.java b/src/main/java/org/scijava/annotations/AnnotationProcessor.java index 8982527e0..e9acebd7c 100644 --- a/src/main/java/org/scijava/annotations/AnnotationProcessor.java +++ b/src/main/java/org/scijava/annotations/AnnotationProcessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7ef216860..98ec12da7 100644 --- a/src/main/java/org/scijava/annotations/ByteCodeAnalyzer.java +++ b/src/main/java/org/scijava/annotations/ByteCodeAnalyzer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 145252203..1f52f9565 100644 --- a/src/main/java/org/scijava/annotations/DirectoryIndexer.java +++ b/src/main/java/org/scijava/annotations/DirectoryIndexer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 053103e8c..07e690a01 100644 --- a/src/main/java/org/scijava/annotations/EclipseHelper.java +++ b/src/main/java/org/scijava/annotations/EclipseHelper.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,6 +40,7 @@ import java.util.jar.JarFile; import java.util.jar.Manifest; +import org.scijava.Context; import org.scijava.util.FileUtils; /** @@ -297,7 +295,7 @@ else if (file.isDirectory()) { */ public static void main(final String... args) { System.setProperty(FORCE_ANNOTATION_INDEX_PROPERTY, "true"); - updateAnnotationIndex(Thread.currentThread().getContextClassLoader()); + updateAnnotationIndex(Context.getClassLoader()); } } diff --git a/src/main/java/org/scijava/annotations/Index.java b/src/main/java/org/scijava/annotations/Index.java index 23348cd80..dd56ab83e 100644 --- a/src/main/java/org/scijava/annotations/Index.java +++ b/src/main/java/org/scijava/annotations/Index.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b047e8075..67aab711f 100644 --- a/src/main/java/org/scijava/annotations/IndexItem.java +++ b/src/main/java/org/scijava/annotations/IndexItem.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d716978ae..894874238 100644 --- a/src/main/java/org/scijava/annotations/IndexReader.java +++ b/src/main/java/org/scijava/annotations/IndexReader.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2916d0a78..deb8f7d65 100644 --- a/src/main/java/org/scijava/annotations/Indexable.java +++ b/src/main/java/org/scijava/annotations/Indexable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 11d0929aa..5b3d0d129 100644 --- a/src/main/java/org/scijava/annotations/legacy/LegacyReader.java +++ b/src/main/java/org/scijava/annotations/legacy/LegacyReader.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 14003cc24..eaa37331d 100644 --- a/src/main/java/org/scijava/app/AbstractApp.java +++ b/src/main/java/org/scijava/app/AbstractApp.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 641c12778..bf4bf0721 100644 --- a/src/main/java/org/scijava/app/App.java +++ b/src/main/java/org/scijava/app/App.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -147,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 34c3dc4b9..582860a36 100644 --- a/src/main/java/org/scijava/app/AppService.java +++ b/src/main/java/org/scijava/app/AppService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 918501003..8a97162b6 100644 --- a/src/main/java/org/scijava/app/DefaultAppService.java +++ b/src/main/java/org/scijava/app/DefaultAppService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a58987ed2..38e3e555d 100644 --- a/src/main/java/org/scijava/app/DefaultStatusService.java +++ b/src/main/java/org/scijava/app/DefaultStatusService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6cb97fb8b..067184141 100644 --- a/src/main/java/org/scijava/app/SciJavaApp.java +++ b/src/main/java/org/scijava/app/SciJavaApp.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c0f20dd08..7896b9b4a 100644 --- a/src/main/java/org/scijava/app/StatusService.java +++ b/src/main/java/org/scijava/app/StatusService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1866e18a6..d1c055557 100644 --- a/src/main/java/org/scijava/app/event/StatusEvent.java +++ b/src/main/java/org/scijava/app/event/StatusEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 24c592a0f..aaa51c43d 100644 --- a/src/main/java/org/scijava/cache/CacheService.java +++ b/src/main/java/org/scijava/cache/CacheService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4111a45a6..ffba4ebb4 100644 --- a/src/main/java/org/scijava/cache/DefaultCacheService.java +++ b/src/main/java/org/scijava/cache/DefaultCacheService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1843cf1be..3e99f2d3f 100644 --- a/src/main/java/org/scijava/command/Command.java +++ b/src/main/java/org/scijava/command/Command.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4acc3f163..f0b2bd34c 100644 --- a/src/main/java/org/scijava/command/CommandInfo.java +++ b/src/main/java/org/scijava/command/CommandInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -55,6 +52,7 @@ import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; import org.scijava.plugin.PluginInfo; +import org.scijava.service.Service; import org.scijava.util.ClassUtils; import org.scijava.util.StringMaker; import org.scijava.util.Types; @@ -463,7 +461,8 @@ private void checkFields(final Class type) { } final String name = f.getName(); - if (inputMap.containsKey(name) || outputMap.containsKey(name)) { + if ((inputMap.containsKey(name) || outputMap.containsKey(name)) + && !Service.class.isAssignableFrom(f.getType())) { // NB: Shadowed parameters are bad because they are ambiguous. final String error = "Invalid duplicate parameter: " + f; problems.add(new ValidityProblem(error)); diff --git a/src/main/java/org/scijava/command/CommandModule.java b/src/main/java/org/scijava/command/CommandModule.java index b675c59a5..bef02fbd5 100644 --- a/src/main/java/org/scijava/command/CommandModule.java +++ b/src/main/java/org/scijava/command/CommandModule.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 862bc3643..b9e602de5 100644 --- a/src/main/java/org/scijava/command/CommandModuleItem.java +++ b/src/main/java/org/scijava/command/CommandModuleItem.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 589da8fe8..502113a69 100644 --- a/src/main/java/org/scijava/command/CommandService.java +++ b/src/main/java/org/scijava/command/CommandService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2754d4f7f..ae9e3830e 100644 --- a/src/main/java/org/scijava/command/ContextCommand.java +++ b/src/main/java/org/scijava/command/ContextCommand.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ca8c412d1..f1d59a2b0 100644 --- a/src/main/java/org/scijava/command/DefaultCommandService.java +++ b/src/main/java/org/scijava/command/DefaultCommandService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b56a0bac6..5d165192d 100644 --- a/src/main/java/org/scijava/command/DynamicCommand.java +++ b/src/main/java/org/scijava/command/DynamicCommand.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,7 +36,9 @@ import org.scijava.Contextual; import org.scijava.NullContextException; import org.scijava.module.DefaultMutableModule; +import org.scijava.module.ModuleService; import org.scijava.plugin.Parameter; +import org.scijava.plugin.PluginService; import org.scijava.util.ClassUtils; /** @@ -60,6 +59,12 @@ public abstract class DynamicCommand extends DefaultMutableModule implements @Parameter private CommandService commandService; + @Parameter + protected PluginService pluginService; + + @Parameter + protected ModuleService moduleService; + private DynamicCommandInfo info; /** Reason for cancelation, or null if not canceled. */ @@ -71,7 +76,8 @@ public abstract class DynamicCommand extends DefaultMutableModule implements public DynamicCommandInfo getInfo() { if (info == null) { // NB: Create dynamic metadata lazily. - final CommandInfo commandInfo = commandService.getCommand(getClass()); + CommandInfo commandInfo = commandService.getCommand(getClass()); + if (commandInfo == null) commandInfo = new CommandInfo(getClass()); info = new DynamicCommandInfo(commandInfo, getClass()); } return info; @@ -87,7 +93,7 @@ public Object getInput(final String name) { @Override public Object getOutput(final String name) { final Field field = getInfo().getOutputField(name); - if (field == null) return super.getInput(name); + if (field == null) return super.getOutput(name); return ClassUtils.getValue(field, this); } @@ -144,4 +150,15 @@ public String getCancelReason() { public void uncancel() { cancelReason = null; } + + // -- Internal methods -- + + /** + * Persists current input values. Use e.g. for {@link InteractiveCommand}s + * that want to persist values as they change, since interactive commands do + * not complete the module execution lifecycle normally. + */ + protected void saveInputs() { + moduleService.saveInputs(this); + } } diff --git a/src/main/java/org/scijava/command/DynamicCommandInfo.java b/src/main/java/org/scijava/command/DynamicCommandInfo.java index a45f4b1ac..738521744 100644 --- a/src/main/java/org/scijava/command/DynamicCommandInfo.java +++ b/src/main/java/org/scijava/command/DynamicCommandInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -51,9 +48,9 @@ * Helper class for maintaining a {@link DynamicCommand}'s associated * {@link ModuleInfo}. *

- * The {@link CommandService} has a plain {@link CommandInfo} object in its - * index, populated from the {@link DynamicCommand}'s @{@link Plugin} - * annotation. So this class adapts that object, delegating to it for the + * This class wraps a plain {@link CommandInfo} object (e.g. from the + * {@link CommandService}'s index, present due to an @{@link Plugin} annotation + * on the {@link DynamicCommand} class), delegating to it for the * {@link UIDetails} methods. The plain {@link CommandInfo} cannot be used * as-is, however, because we need to override the {@link ModuleInfo} methods as * well as provide metadata manipulation functionality such as diff --git a/src/main/java/org/scijava/command/Inputs.java b/src/main/java/org/scijava/command/Inputs.java new file mode 100644 index 000000000..a97d282f2 --- /dev/null +++ b/src/main/java/org/scijava/command/Inputs.java @@ -0,0 +1,102 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.command; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.scijava.Context; +import org.scijava.module.process.PreprocessorPlugin; + +/** + * A way to build a dynamic set of inputs, whose values are then harvested by + * the preprocessing framework. + *

+ * The {@link #run()} method of this command does nothing. If you want something + * custom to happen during execution, use a normal {@link Command} instead: + * either implement {@link Command directly}, or extend {@link ContextCommand} + * or {@link DynamicCommand}. + *

+ *

+ * Here is are some examples of usage: + *

+ * + *
+ * {@code
+ * // Single input, no configuration.
+ * Inputs inputs = new Inputs(context);
+ * inputs.addInput("sigma", Double.class);
+ * Double sigma = (Double) inputs.harvest().get("sigma");
+ *
+ * // Two inputs, no configuration.
+ * Inputs inputs = new Inputs(context);
+ * inputs.addInput("name", String.class);
+ * inputs.addInput("age", Integer.class);
+ * Map values = inputs.harvest();
+ * String name = (String) values.get("name");
+ * Integer age = (Integer) values.get("age");
+ *
+ * // Inputs with configuration.
+ * Inputs inputs = new Inputs(context);
+ * MutableModuleItem wordInput = inputs.addInput("word", String.class);
+ * wordInput.setLabel("Favorite word");
+ * wordInput.setChoices(Arrays.asList("quick", "brown", "fox"));
+ * wordInput.setDefaultValue("fox");
+ * MutableModuleItem opacityInput = inputs.addInput("opacity", Double.class);
+ * opacityInput.setMinimumValue(0.0);
+ * opacityInput.setMaximumValue(1.0);
+ * opacityInput.setDefaultValue(0.5);
+ * opacityInput.setWidgetStyle(NumberWidget.SCROLL_BAR_STYLE);
+ * inputs.harvest();
+ * String word = wordInput.getValue(inputs);
+ * Double opacity = opacityInput.getValue(inputs);
+ * }
+ * 
+ * + * @author Curtis Rueden + */ +public final class Inputs extends DynamicCommand { + + public Inputs(final Context context) { + context.inject(this); + } + + public Map harvest() { + try { + final List pre = // + pluginService.createInstancesOfType(PreprocessorPlugin.class); + return moduleService.run(this, pre, null).get().getInputs(); + } + catch (final InterruptedException | ExecutionException exc) { + throw new RuntimeException(exc); + } + } +} diff --git a/src/main/java/org/scijava/command/Interactive.java b/src/main/java/org/scijava/command/Interactive.java index 74ad4cfee..6f4d93375 100644 --- a/src/main/java/org/scijava/command/Interactive.java +++ b/src/main/java/org/scijava/command/Interactive.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 117485838..1edf9a4b3 100644 --- a/src/main/java/org/scijava/command/InteractiveCommand.java +++ b/src/main/java/org/scijava/command/InteractiveCommand.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -96,6 +93,7 @@ public InteractiveCommand(final String... listenerNames) { public void preview() { // NB: Interactive commands call run upon any parameter change. run(); + saveInputs(); } @Override diff --git a/src/main/java/org/scijava/command/ModuleCommand.java b/src/main/java/org/scijava/command/ModuleCommand.java index 4abc0fee1..2a2bb9469 100644 --- a/src/main/java/org/scijava/command/ModuleCommand.java +++ b/src/main/java/org/scijava/command/ModuleCommand.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8ee57832d..330d8472c 100644 --- a/src/main/java/org/scijava/command/Previewable.java +++ b/src/main/java/org/scijava/command/Previewable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 74530bcec..763d324cf 100644 --- a/src/main/java/org/scijava/command/UnimplementedCommand.java +++ b/src/main/java/org/scijava/command/UnimplementedCommand.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a6673e243..e5dac33f2 100644 --- a/src/main/java/org/scijava/command/console/RunArgument.java +++ b/src/main/java/org/scijava/command/console/RunArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 25024e0da..d823f05f9 100644 --- a/src/main/java/org/scijava/command/run/CommandCodeRunner.java +++ b/src/main/java/org/scijava/command/run/CommandCodeRunner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cde13bf0d..eff1cf185 100644 --- a/src/main/java/org/scijava/console/AbstractConsoleArgument.java +++ b/src/main/java/org/scijava/console/AbstractConsoleArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4e645ced5..b51e8a549 100644 --- a/src/main/java/org/scijava/console/ConsoleArgument.java +++ b/src/main/java/org/scijava/console/ConsoleArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f5bd055a8..e869933ed 100644 --- a/src/main/java/org/scijava/console/ConsoleService.java +++ b/src/main/java/org/scijava/console/ConsoleService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6b366a860..909aa3ea0 100644 --- a/src/main/java/org/scijava/console/ConsoleUtils.java +++ b/src/main/java/org/scijava/console/ConsoleUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8783e1eb9..c129e56d2 100644 --- a/src/main/java/org/scijava/console/DefaultConsoleService.java +++ b/src/main/java/org/scijava/console/DefaultConsoleService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d1f380f20..1cc9803e9 100644 --- a/src/main/java/org/scijava/console/MultiOutputStream.java +++ b/src/main/java/org/scijava/console/MultiOutputStream.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 659f52b9f..a194dc24d 100644 --- a/src/main/java/org/scijava/console/MultiPrintStream.java +++ b/src/main/java/org/scijava/console/MultiPrintStream.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 663d51de7..dddd58e36 100644 --- a/src/main/java/org/scijava/console/OutputEvent.java +++ b/src/main/java/org/scijava/console/OutputEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f3657c1ca..c86479e10 100644 --- a/src/main/java/org/scijava/console/OutputListener.java +++ b/src/main/java/org/scijava/console/OutputListener.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c174d5aec..aa2f2ddfd 100644 --- a/src/main/java/org/scijava/console/SystemPropertyArgument.java +++ b/src/main/java/org/scijava/console/SystemPropertyArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -47,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 b15c52de0..18d995afd 100644 --- a/src/main/java/org/scijava/convert/AbstractConvertService.java +++ b/src/main/java/org/scijava/convert/AbstractConvertService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,145 +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()) { - addIfMatches(source, converter.getInputType(), converter.getOutputType(), compatibleClasses); - } - - 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 2c6b4165c..a7f252b3c 100644 --- a/src/main/java/org/scijava/convert/AbstractConverter.java +++ b/src/main/java/org/scijava/convert/AbstractConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,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 */ @@ -75,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) { @@ -141,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 new file mode 100644 index 000000000..f9b979947 --- /dev/null +++ b/src/main/java/org/scijava/convert/AbstractDelegateConverter.java @@ -0,0 +1,57 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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 org.scijava.plugin.Parameter; + +/** + * Abstract superclass for {@link Converter} plugins that delegate to other + * converters to chain two conversion steps together. + * + * @author Jan Eglinger + * @param the input type + * @param the delegate type + * @param the output type + */ +public abstract class AbstractDelegateConverter extends + AbstractConverter +{ + + @Parameter + private ConvertService convertService; + + @Override + public T convert(Object src, Class dest) { + D delegate = convertService.convert(src, getDelegateType()); + return convertService.convert(delegate, dest); + } + + protected abstract Class getDelegateType(); +} diff --git a/src/main/java/org/scijava/convert/ArrayConverters.java b/src/main/java/org/scijava/convert/ArrayConverters.java index 70b0d927c..18d5f5916 100644 --- a/src/main/java/org/scijava/convert/ArrayConverters.java +++ b/src/main/java/org/scijava/convert/ArrayConverters.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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..d141d5454 --- /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 - 2025 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 77f5479eb..1e4e80ca6 100644 --- a/src/main/java/org/scijava/convert/CastingConverter.java +++ b/src/main/java/org/scijava/convert/CastingConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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; @@ -40,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 @@ -48,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 409af735f..65ce220ba 100644 --- a/src/main/java/org/scijava/convert/ConversionRequest.java +++ b/src/main/java/org/scijava/convert/ConversionRequest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 49bf952ee..84e56de9d 100644 --- a/src/main/java/org/scijava/convert/ConvertService.java +++ b/src/main/java/org/scijava/convert/ConvertService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,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 @@ -54,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 195fa4b07..5b0544369 100644 --- a/src/main/java/org/scijava/convert/Converter.java +++ b/src/main/java/org/scijava/convert/Converter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,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 @@ -58,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 @@ -105,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 @@ -129,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. @@ -173,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 2176e0398..d14e64dce 100644 --- a/src/main/java/org/scijava/convert/DefaultConvertService.java +++ b/src/main/java/org/scijava/convert/DefaultConvertService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,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 f065627cf..b9f53256d 100644 --- a/src/main/java/org/scijava/convert/DefaultConverter.java +++ b/src/main/java/org/scijava/convert/DefaultConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,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; /** @@ -76,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); @@ -84,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 @@ -152,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; @@ -222,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 @@ -247,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(); @@ -291,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 386279774..f4e8e86e7 100644 --- a/src/main/java/org/scijava/convert/FileListConverters.java +++ b/src/main/java/org/scijava/convert/FileListConverters.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 @@ -38,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; @@ -52,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 { @@ -75,7 +71,7 @@ public Class getInputType() { } - @Plugin(type = Converter.class, priority = Priority.NORMAL) + @Plugin(type = Converter.class) public static class StringToFileArrayConverter extends AbstractConverter { @@ -86,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()]); @@ -107,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 { @@ -130,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..9a6960566 --- /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 - 2025 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 cc3977d8a..b43a5cecf 100644 --- a/src/main/java/org/scijava/convert/NullConverter.java +++ b/src/main/java/org/scijava/convert/NullConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,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 @@ -98,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 e7827463f..2f52ba40d 100644 --- a/src/main/java/org/scijava/convert/NumberConverters.java +++ b/src/main/java/org/scijava/convert/NumberConverters.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 74f4fecb1..34b5a22a1 100644 --- a/src/main/java/org/scijava/convert/NumberToBigDecimalConverter.java +++ b/src/main/java/org/scijava/convert/NumberToBigDecimalConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 daf688867..6877d4b6b 100644 --- a/src/main/java/org/scijava/convert/NumberToBigIntegerConverter.java +++ b/src/main/java/org/scijava/convert/NumberToBigIntegerConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 49bd310aa..d32b0a751 100644 --- a/src/main/java/org/scijava/convert/NumberToDoubleConverter.java +++ b/src/main/java/org/scijava/convert/NumberToDoubleConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 dacd8496c..cc9a6b31f 100644 --- a/src/main/java/org/scijava/convert/NumberToFloatConverter.java +++ b/src/main/java/org/scijava/convert/NumberToFloatConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5d43e22a1..799ac9ac7 100644 --- a/src/main/java/org/scijava/convert/NumberToIntegerConverter.java +++ b/src/main/java/org/scijava/convert/NumberToIntegerConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e22864ed6..34df15429 100644 --- a/src/main/java/org/scijava/convert/NumberToLongConverter.java +++ b/src/main/java/org/scijava/convert/NumberToLongConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 31e3358e6..4ad78680d 100644 --- a/src/main/java/org/scijava/convert/NumberToNumberConverter.java +++ b/src/main/java/org/scijava/convert/NumberToNumberConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -46,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()) { @@ -58,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 1714eeae0..858fdd13b 100644 --- a/src/main/java/org/scijava/convert/NumberToShortConverter.java +++ b/src/main/java/org/scijava/convert/NumberToShortConverter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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..1a066296e --- /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 - 2025 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 d407fcb99..32b048a30 100644 --- a/src/main/java/org/scijava/convert/PrimitiveArrayUnwrapper.java +++ b/src/main/java/org/scijava/convert/PrimitiveArrayUnwrapper.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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 46a07a4ed..549527f4e 100644 --- a/src/main/java/org/scijava/convert/PrimitiveArrayWrapper.java +++ b/src/main/java/org/scijava/convert/PrimitiveArrayWrapper.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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..8b0996095 --- /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 - 2025 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 new file mode 100644 index 000000000..f8f407a87 --- /dev/null +++ b/src/main/java/org/scijava/convert/StringToNumberConverter.java @@ -0,0 +1,99 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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 org.scijava.plugin.Plugin; +import org.scijava.util.Types; + +/** + * Converts a {@link String} to a {@link Number}. Currently handles all boxed + * and unboxed primitives, along with the Numbers. In particular, + * {@link String}s converted {@link Number}s are just {@link Double}s, as this + * features the broadest range of integers. + * + * @author Gabriel Selzer + */ +@Plugin(type = Converter.class) +public class StringToNumberConverter extends AbstractConverter { + + @Override + @SuppressWarnings("unchecked") + public T convert(Object src, Class dest) { + // ensure type is well-behaved, rather than a primitive type + Class saneDest = sane(dest); + if (!(src instanceof String)) throw new IllegalArgumentException( + "Expected src to be a String but got a " + src.getClass()); + if (!(Number.class.isAssignableFrom(saneDest))) + throw new IllegalArgumentException( + "Expected dest to be Number.class (or a subclass of Number, or a numerical primitive), but got " + + saneDest); + String srcString = (String) src; + if (saneDest == Byte.class) return (T) new Byte(srcString); + if (saneDest == Short.class) return (T) new Short(srcString); + if (saneDest == Integer.class) return (T) new Integer(srcString); + if (saneDest == Long.class) return (T) new Long(srcString); + if (saneDest == Float.class) return (T) new Float(srcString); + if (saneDest == Double.class) return (T) new Double(srcString); + else throw new IllegalArgumentException("Unknown destination type: " + + saneDest); + } + + @Override + public Class getOutputType() { + return Number.class; + } + + @Override + public Class getInputType() { + return String.class; + } + + @Override + public boolean canConvert(Object src, Class dest) { + if (!Types.isAssignable(src.getClass(), String.class)) return false; + // The only way to know if the conversion is valid is to actually do it. + try { + String srcString = (String) src; + sane(dest).getConstructor(String.class).newInstance(srcString); + return true; + } + catch (Exception e) { + return false; + } + } + + // -- Helper functionality -- // + + @SuppressWarnings("unchecked") + private Class sane(Class c) { + if (c == Number.class) return (Class) Double.class; + return Types.box(c); + } +} diff --git a/src/main/java/org/scijava/display/AbstractDisplay.java b/src/main/java/org/scijava/display/AbstractDisplay.java index f4eff12aa..c1fbd2ee0 100644 --- a/src/main/java/org/scijava/display/AbstractDisplay.java +++ b/src/main/java/org/scijava/display/AbstractDisplay.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 58d41b983..fd5bc184e 100644 --- a/src/main/java/org/scijava/display/ActiveDisplayPreprocessor.java +++ b/src/main/java/org/scijava/display/ActiveDisplayPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 542a88f5b..e75317060 100644 --- a/src/main/java/org/scijava/display/DefaultDisplay.java +++ b/src/main/java/org/scijava/display/DefaultDisplay.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a8e0e6ade..b125937d4 100644 --- a/src/main/java/org/scijava/display/DefaultDisplayService.java +++ b/src/main/java/org/scijava/display/DefaultDisplayService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 35d9285ec..ab6044b12 100644 --- a/src/main/java/org/scijava/display/DefaultTextDisplay.java +++ b/src/main/java/org/scijava/display/DefaultTextDisplay.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e51c819bf..4886b3a1e 100644 --- a/src/main/java/org/scijava/display/Display.java +++ b/src/main/java/org/scijava/display/Display.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0bfdfd77b..a97064ce5 100644 --- a/src/main/java/org/scijava/display/DisplayPostprocessor.java +++ b/src/main/java/org/scijava/display/DisplayPostprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 204b72608..dc2654396 100644 --- a/src/main/java/org/scijava/display/DisplayService.java +++ b/src/main/java/org/scijava/display/DisplayService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c57d69244..4b38e060e 100644 --- a/src/main/java/org/scijava/display/Displayable.java +++ b/src/main/java/org/scijava/display/Displayable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 46be07e94..f6eddb44f 100644 --- a/src/main/java/org/scijava/display/TextDisplay.java +++ b/src/main/java/org/scijava/display/TextDisplay.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4edf3e210..7af76b8b4 100644 --- a/src/main/java/org/scijava/display/event/DisplayActivatedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayActivatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 56202566b..eab8406e7 100644 --- a/src/main/java/org/scijava/display/event/DisplayCreatedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayCreatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 30a461d51..aeda51f31 100644 --- a/src/main/java/org/scijava/display/event/DisplayDeletedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayDeletedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a604634fd..22bd5ffeb 100644 --- a/src/main/java/org/scijava/display/event/DisplayEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 dbac42c23..d609a2391 100644 --- a/src/main/java/org/scijava/display/event/DisplayUpdatedEvent.java +++ b/src/main/java/org/scijava/display/event/DisplayUpdatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8ef95d6a1..877529707 100644 --- a/src/main/java/org/scijava/display/event/input/InputEvent.java +++ b/src/main/java/org/scijava/display/event/input/InputEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 93f8741f6..3acf2bece 100644 --- a/src/main/java/org/scijava/display/event/input/KyEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d86783a0c..2c812389b 100644 --- a/src/main/java/org/scijava/display/event/input/KyPressedEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyPressedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 81f003f47..2ce597b48 100644 --- a/src/main/java/org/scijava/display/event/input/KyReleasedEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyReleasedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 52354fc5a..a345748ab 100644 --- a/src/main/java/org/scijava/display/event/input/KyTypedEvent.java +++ b/src/main/java/org/scijava/display/event/input/KyTypedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 737edb758..2e728f3af 100644 --- a/src/main/java/org/scijava/display/event/input/MsButtonEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsButtonEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 206cdea81..8962c1a80 100644 --- a/src/main/java/org/scijava/display/event/input/MsClickedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsClickedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a1d73920f..226453319 100644 --- a/src/main/java/org/scijava/display/event/input/MsDraggedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsDraggedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c68ca8fce..1ee9e2cf5 100644 --- a/src/main/java/org/scijava/display/event/input/MsEnteredEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsEnteredEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ffc1cd08c..5e1d047f0 100644 --- a/src/main/java/org/scijava/display/event/input/MsEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b0ea0b037..f60eb58b2 100644 --- a/src/main/java/org/scijava/display/event/input/MsExitedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsExitedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e0d7045a8..ba737a960 100644 --- a/src/main/java/org/scijava/display/event/input/MsMovedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsMovedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4c3e3fd99..19ca38bfd 100644 --- a/src/main/java/org/scijava/display/event/input/MsPressedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsPressedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7fdbc15f8..219e62b73 100644 --- a/src/main/java/org/scijava/display/event/input/MsReleasedEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsReleasedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c0da07dc4..8f0ec7c6b 100644 --- a/src/main/java/org/scijava/display/event/input/MsWheelEvent.java +++ b/src/main/java/org/scijava/display/event/input/MsWheelEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e070b45a4..380cc2185 100644 --- a/src/main/java/org/scijava/display/event/window/WinActivatedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinActivatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 11bb065a3..7e11f2581 100644 --- a/src/main/java/org/scijava/display/event/window/WinClosedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinClosedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 51b9e6402..f8573f746 100644 --- a/src/main/java/org/scijava/display/event/window/WinClosingEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinClosingEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d3f994aef..c1f8f7d03 100644 --- a/src/main/java/org/scijava/display/event/window/WinDeactivatedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinDeactivatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 68a182f04..770c05f30 100644 --- a/src/main/java/org/scijava/display/event/window/WinDeiconifiedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinDeiconifiedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6eda6b191..b691b0a71 100644 --- a/src/main/java/org/scijava/display/event/window/WinEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 910acbadc..4486a5630 100644 --- a/src/main/java/org/scijava/display/event/window/WinIconifiedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinIconifiedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1b4bd8b09..e34298e6c 100644 --- a/src/main/java/org/scijava/display/event/window/WinOpenedEvent.java +++ b/src/main/java/org/scijava/display/event/window/WinOpenedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b665645c1..da91dc3e8 100644 --- a/src/main/java/org/scijava/download/DefaultDownloadService.java +++ b/src/main/java/org/scijava/download/DefaultDownloadService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5ee047fa8..73471ebed 100644 --- a/src/main/java/org/scijava/download/DiskLocationCache.java +++ b/src/main/java/org/scijava/download/DiskLocationCache.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ef2e0b0e1..56d00f71f 100644 --- a/src/main/java/org/scijava/download/Download.java +++ b/src/main/java/org/scijava/download/Download.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 de74162f0..abc4c8294 100644 --- a/src/main/java/org/scijava/download/DownloadService.java +++ b/src/main/java/org/scijava/download/DownloadService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4f6b72471..ee49eed26 100644 --- a/src/main/java/org/scijava/download/LocationCache.java +++ b/src/main/java/org/scijava/download/LocationCache.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0f810c9c6..4c7d5ef3a 100644 --- a/src/main/java/org/scijava/download/MultiWriteHandle.java +++ b/src/main/java/org/scijava/download/MultiWriteHandle.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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..2f43d2105 --- /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 - 2025 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 26b9b7bcf..472c6b03e 100644 --- a/src/main/java/org/scijava/event/ContextDisposingEvent.java +++ b/src/main/java/org/scijava/event/ContextDisposingEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7d262054c..72e269077 100644 --- a/src/main/java/org/scijava/event/DefaultEventBus.java +++ b/src/main/java/org/scijava/event/DefaultEventBus.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,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. *

* @@ -62,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; } @@ -115,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 7835f5087..c0d397cb1 100644 --- a/src/main/java/org/scijava/event/DefaultEventHistory.java +++ b/src/main/java/org/scijava/event/DefaultEventHistory.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 07530827d..d627ce668 100644 --- a/src/main/java/org/scijava/event/DefaultEventService.java +++ b/src/main/java/org/scijava/event/DefaultEventService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,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; @@ -142,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) { @@ -265,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 94db61dcd..794e3e3fa 100644 --- a/src/main/java/org/scijava/event/EventDetails.java +++ b/src/main/java/org/scijava/event/EventDetails.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 386713bc6..56283f452 100644 --- a/src/main/java/org/scijava/event/EventHandler.java +++ b/src/main/java/org/scijava/event/EventHandler.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,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 6d0dbc100..e54425120 100644 --- a/src/main/java/org/scijava/event/EventHistory.java +++ b/src/main/java/org/scijava/event/EventHistory.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b74804836..9beecf79f 100644 --- a/src/main/java/org/scijava/event/EventHistoryListener.java +++ b/src/main/java/org/scijava/event/EventHistoryListener.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4d046e5a7..00ef9d7f0 100644 --- a/src/main/java/org/scijava/event/EventService.java +++ b/src/main/java/org/scijava/event/EventService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -128,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 1233b0913..bb05a8f40 100644 --- a/src/main/java/org/scijava/event/EventSubscriber.java +++ b/src/main/java/org/scijava/event/EventSubscriber.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -47,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 f61edc56b..2fcc6876d 100644 --- a/src/main/java/org/scijava/event/SciJavaEvent.java +++ b/src/main/java/org/scijava/event/SciJavaEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +30,7 @@ package org.scijava.event; import org.scijava.AbstractContextual; +import org.scijava.util.DebugUtils; /** * Base class for all SciJava events. @@ -83,6 +81,14 @@ public StackTraceElement[] getStackTrace() { return stackTrace; } + /** + * Gets a stack trace for the calling thread when the event was published. + * This method is useful for debugging what triggered an event. + */ + public String dumpStack() { + return DebugUtils.getStackDump(getCallingThread(), getStackTrace()); + } + // Object methods -- @Override 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 5ac542926..c1296cfb6 100644 --- a/src/main/java/org/scijava/input/Accelerator.java +++ b/src/main/java/org/scijava/input/Accelerator.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 32317193e..2b3506c07 100644 --- a/src/main/java/org/scijava/input/DefaultInputService.java +++ b/src/main/java/org/scijava/input/DefaultInputService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b6a8567e6..21df50b23 100644 --- a/src/main/java/org/scijava/input/InputModifiers.java +++ b/src/main/java/org/scijava/input/InputModifiers.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a3541422d..a38c638bc 100644 --- a/src/main/java/org/scijava/input/InputService.java +++ b/src/main/java/org/scijava/input/InputService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 430f97f0c..0e0ec35e1 100644 --- a/src/main/java/org/scijava/input/KeyCode.java +++ b/src/main/java/org/scijava/input/KeyCode.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -55,7 +52,7 @@ public enum KeyCode { CANCEL(0x03), /** Clear. */ - CLEAR(0x0C), + CLEAR(0x0c), /** Shift (left or right). */ SHIFT(0x10), @@ -73,7 +70,7 @@ public enum KeyCode { CAPS_LOCK(0x14), /** Escape. */ - ESCAPE(0x1B), + ESCAPE(0x1b), /** Space (' '). */ SPACE(0x20), @@ -103,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), @@ -145,10 +142,10 @@ public enum KeyCode { NUM9(0x39), /** Semicolon (';'). */ - SEMICOLON(0x3B), + SEMICOLON(0x3b), /** Equals ('='). */ - EQUALS(0x3D), + EQUALS(0x3d), /** The letter A. */ A(0x41), @@ -178,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), @@ -226,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), @@ -268,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), @@ -324,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), @@ -495,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), @@ -566,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); @@ -635,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 833298a89..8d6d55991 100644 --- a/src/main/java/org/scijava/input/MouseCursor.java +++ b/src/main/java/org/scijava/input/MouseCursor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6053405d8..7e7782572 100644 --- a/src/main/java/org/scijava/io/AbstractIOPlugin.java +++ b/src/main/java/org/scijava/io/AbstractIOPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +29,60 @@ package org.scijava.io; +import org.scijava.io.location.Location; +import org.scijava.io.location.LocationService; import org.scijava.plugin.AbstractHandlerPlugin; +import org.scijava.plugin.Parameter; + +import java.io.IOException; +import java.net.URISyntaxException; /** * Abstract base class for {@link IOPlugin}s. * * @author Curtis Rueden */ -public abstract class AbstractIOPlugin extends AbstractHandlerPlugin - implements IOPlugin +public abstract class AbstractIOPlugin extends + AbstractHandlerPlugin implements IOPlugin { - // NB: No implementation needed. + + @Parameter + private LocationService locationService; + + @Override + public boolean supportsOpen(final String source) { + try { + return supportsOpen(locationService.resolve(source)); + } catch (URISyntaxException e) { + return false; + } + } + + @Override + public boolean supportsSave(final String destination) { + try { + return supportsSave(locationService.resolve(destination)); + } catch (URISyntaxException e) { + return false; + } + } + + @Override + public void save(final D data, final String destination) throws IOException { + try { + save(data, locationService.resolve(destination)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + + @Override + public D open(final String destination) throws IOException { + try { + return open(locationService.resolve(destination)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + } diff --git a/src/main/java/org/scijava/io/AbstractTypedIOService.java b/src/main/java/org/scijava/io/AbstractTypedIOService.java new file mode 100644 index 000000000..28cd7b96f --- /dev/null +++ b/src/main/java/org/scijava/io/AbstractTypedIOService.java @@ -0,0 +1,140 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io; + +import org.scijava.io.location.Location; +import org.scijava.io.location.LocationService; +import org.scijava.plugin.AbstractHandlerService; +import org.scijava.plugin.Parameter; + +import java.io.IOException; +import java.net.URISyntaxException; + +/** + * Abstract base class for typed {@link IOPlugin}s. + * + * @author Curtis Rueden + * @author Deborah Schmidt + */ +public abstract class AbstractTypedIOService extends AbstractHandlerService> implements TypedIOService +{ + + @Parameter + private LocationService locationService; + + @Parameter + private IOService ioService; + + @Override + public D open(String source) throws IOException { + try { + return open(locationService.resolve(source)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + + @Override + public D open(Location source) throws IOException { + IOPlugin opener = ioService().getOpener(source); + try { + Class ignored = (Class) opener.getDataType(); + return (D) opener.open(source); + } + catch(ClassCastException e) { + throw new UnsupportedOperationException("No compatible opener found."); + } + } + + @Override + public void save(D data, String destination) throws IOException { + try { + save(data, locationService.resolve(destination)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + + @Override + public void save(D data, Location destination) throws IOException { + IOPlugin saver = ioService().getSaver(data, destination); + if (saver != null) { + saver.save(data, destination); + } + else { + throw new UnsupportedOperationException("No compatible saver found."); + } + } + + @Override + public boolean canOpen(String source) { + try { + return canOpen(locationService.resolve(source)); + } catch (URISyntaxException e) { + return false; + } + } + + @Override + public boolean canOpen(Location source) { + IOPlugin opener = ioService().getOpener(source); + if (opener == null) return false; + try { + Class ignored = (Class) (opener.getDataType()); + return true; + } catch(ClassCastException e) { + return false; + } + } + + @Override + public boolean canSave(D data, String source) { + try { + return canSave(data, locationService.resolve(source)); + } catch (URISyntaxException e) { + return false; + } + } + + @Override + public boolean canSave(D data, Location destination) { + IOPlugin saver = ioService.getSaver(data, destination); + if (saver == null) return false; + return saver.supportsSave(destination); + } + + protected LocationService locationService() { + return locationService; + } + + protected IOService ioService() { + return ioService; + } +} diff --git a/src/main/java/org/scijava/io/ByteArrayByteBank.java b/src/main/java/org/scijava/io/ByteArrayByteBank.java index b0b759955..277f9abf2 100644 --- a/src/main/java/org/scijava/io/ByteArrayByteBank.java +++ b/src/main/java/org/scijava/io/ByteArrayByteBank.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 397b22133..fa6352140 100644 --- a/src/main/java/org/scijava/io/ByteBank.java +++ b/src/main/java/org/scijava/io/ByteBank.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 70ac00020..183dbcd07 100644 --- a/src/main/java/org/scijava/io/DefaultIOService.java +++ b/src/main/java/org/scijava/io/DefaultIOService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,10 +30,13 @@ package org.scijava.io; import java.io.IOException; +import java.net.URISyntaxException; import org.scijava.event.EventService; import org.scijava.io.event.DataOpenedEvent; import org.scijava.io.event.DataSavedEvent; +import org.scijava.io.location.Location; +import org.scijava.io.location.LocationService; import org.scijava.log.LogService; import org.scijava.plugin.AbstractHandlerService; import org.scijava.plugin.Parameter; @@ -50,7 +50,7 @@ */ @Plugin(type = Service.class) public final class DefaultIOService - extends AbstractHandlerService> implements IOService + extends AbstractHandlerService> implements IOService { @Parameter @@ -59,28 +59,76 @@ public final class DefaultIOService @Parameter private EventService eventService; - // -- IOService methods -- + @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 { + try { + return open(locationService.resolve(source)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + + @Override + public void save(final Object data, final String destination) + throws IOException + { + try { + save(data, locationService.resolve(destination)); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + + @Override + public Object open(final Location source) throws IOException { final IOPlugin opener = getOpener(source); - if (opener == null) return null; // no appropriate IOPlugin + if (opener == null) { + log.error("No opener IOPlugin found for " + source + "."); + return null; + } final Object data = opener.open(source); - if (data == null) return null; // IOPlugin returned no data; canceled? + if (data == null) { + log.warn("Opener IOPlugin " + opener + " returned no data. Canceled?"); + return null; // IOPlugin returned no data; canceled? + } eventService.publish(new DataOpenedEvent(source, data)); return data; } @Override - public void save(final Object data, final String destination) + public void save(final Object data, final Location destination) throws IOException { final IOPlugin saver = getSaver(data, destination); if (saver != null) { saver.save(data, destination); eventService.publish(new DataSavedEvent(destination, data)); + } else { + 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 8bda3c537..1e7f0a85f 100644 --- a/src/main/java/org/scijava/io/DefaultRecentFileService.java +++ b/src/main/java/org/scijava/io/DefaultRecentFileService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,6 +41,8 @@ import org.scijava.event.EventHandler; import org.scijava.event.EventService; import org.scijava.io.event.IOEvent; +import org.scijava.io.location.FileLocation; +import org.scijava.io.location.Location; import org.scijava.menu.MenuConstants; import org.scijava.module.ModuleInfo; import org.scijava.module.ModuleService; @@ -175,11 +174,19 @@ public void initialize() { moduleService.addModules(recentModules.values()); } + @Override + public void dispose() { + clear(); + } + // -- Event handlers -- @EventHandler protected void onEvent(final IOEvent event) { - add(event.getDescriptor()); + final Location loc = event.getLocation(); + if (!(loc instanceof FileLocation)) return; + final FileLocation fileLoc = (FileLocation) loc; + add(fileLoc.getFile().getPath()); } // -- Helper methods -- diff --git a/src/main/java/org/scijava/io/IOPlugin.java b/src/main/java/org/scijava/io/IOPlugin.java index 42781e9a6..ed42dee25 100644 --- a/src/main/java/org/scijava/io/IOPlugin.java +++ b/src/main/java/org/scijava/io/IOPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,7 +30,10 @@ package org.scijava.io; import java.io.IOException; +import java.net.URISyntaxException; +import org.scijava.io.location.Location; +import org.scijava.io.location.LocationService; import org.scijava.plugin.HandlerPlugin; import org.scijava.plugin.Plugin; @@ -51,52 +51,91 @@ * @see Plugin * @see IOService */ -public interface IOPlugin extends HandlerPlugin { +public interface IOPlugin extends HandlerPlugin { /** The type of data opened and/or saved by the plugin. */ Class getDataType(); /** Checks whether the I/O plugin can open data from the given source. */ - @SuppressWarnings("unused") default boolean supportsOpen(final String 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. */ + @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) { + 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. */ + @SuppressWarnings("unused") + default boolean supportsSave(final Location destination) { return false; } /** * Checks whether the I/O plugin can save the given data to the specified - * destination. + * location. */ default boolean supportsSave(final Object data, final String destination) { return supportsSave(destination) && getDataType().isInstance(data); } + default boolean supportsSave(final Object data, final Location destination) { + return supportsSave(destination) && getDataType().isInstance(data); + } + /** Opens data from the given source. */ @SuppressWarnings("unused") default D open(final String source) throws IOException { throw new UnsupportedOperationException(); } - /** Saves the given data to the specified destination. */ + /** Opens data from the given location. */ @SuppressWarnings("unused") + default D open(final Location source) throws IOException { + throw new UnsupportedOperationException(); + } + + /** Saves the given data to the specified destination. */ default void save(final D data, final String destination) throws IOException { + 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. */ + @SuppressWarnings("unused") + default void save(final D data, final Location destination) throws IOException { throw new UnsupportedOperationException(); } // -- Typed methods -- - @Override default boolean supports(final String descriptor) { return supportsOpen(descriptor) || supportsSave(descriptor); } @Override - default Class getType() { - return String.class; + default Class getType() { + return Location.class; } } diff --git a/src/main/java/org/scijava/io/IOService.java b/src/main/java/org/scijava/io/IOService.java index 3858229a9..d26c66ce9 100644 --- a/src/main/java/org/scijava/io/IOService.java +++ b/src/main/java/org/scijava/io/IOService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,6 +31,7 @@ import java.io.IOException; +import org.scijava.io.location.Location; import org.scijava.plugin.HandlerService; import org.scijava.service.SciJavaService; @@ -42,15 +40,21 @@ * * @author Curtis Rueden */ -public interface IOService extends HandlerService>, +public interface IOService extends HandlerService>, SciJavaService { /** * Gets the most appropriate {@link IOPlugin} for opening data from the given - * source. + * location. */ - default IOPlugin getOpener(final String source) { + IOPlugin getOpener(final String source) throws IOException; + + /** + * Gets the most appropriate {@link IOPlugin} for opening data from the given + * location. + */ + default IOPlugin getOpener(Location source) { for (final IOPlugin handler : getInstances()) { if (handler.supportsOpen(source)) return handler; } @@ -59,9 +63,15 @@ default IOPlugin getOpener(final String source) { /** * Gets the most appropriate {@link IOPlugin} for saving data to the given - * destination. + * location. + */ + IOPlugin getSaver(final D data, final String destination) throws IOException; + + /** + * Gets the most appropriate {@link IOPlugin} for saving data to the given + * location. */ - default IOPlugin getSaver(final D data, final String destination) { + default IOPlugin getSaver(D data, Location destination) { for (final IOPlugin handler : getInstances()) { if (handler.supportsSave(data, destination)) { @SuppressWarnings("unchecked") @@ -80,7 +90,7 @@ default IOPlugin getSaver(final D data, final String destination) { * The opener to use is automatically determined based on available * {@link IOPlugin}s; see {@link #getOpener(String)}. *

- * + * * @param source The source (e.g., file path) from which to data should be * loaded. * @return An object representing the loaded data, or null if the source is @@ -89,6 +99,22 @@ default IOPlugin getSaver(final D data, final String destination) { */ Object open(String source) throws IOException; + /** + * Loads data from the given location. + *

+ * The opener to use is automatically determined based on available + * {@link IOPlugin}s; see {@link #getOpener(Location)}. + *

+ * + * @param source The location from which to data should be loaded. + * @return An object representing the loaded data, or null if the source is + * not supported. + * @throws IOException if something goes wrong loading the data. + */ + default Object open(Location source) throws IOException { + throw new UnsupportedOperationException(); + } + /** * Saves data to the given destination. The nature of the destination is left * intentionally general, but the most common example is a file path. @@ -96,7 +122,7 @@ default IOPlugin getSaver(final D data, final String destination) { * The saver to use is automatically determined based on available * {@link IOPlugin}s; see {@link #getSaver(Object, String)}. *

- * + * * @param data The data to be saved to the destination. * @param destination The destination (e.g., file path) to which data should * be saved. @@ -104,6 +130,21 @@ default IOPlugin getSaver(final D data, final String destination) { */ void save(Object data, String destination) throws IOException; + /** + * Saves data to the given location. + *

+ * The saver to use is automatically determined based on available + * {@link IOPlugin}s; see {@link #getSaver(Object, Location)}. + *

+ * + * @param data The data to be saved to the destination. + * @param destination The destination location to which data should be saved. + * @throws IOException if something goes wrong saving the data. + */ + default void save(Object data, Location destination) throws IOException { + throw new UnsupportedOperationException(); + } + // -- HandlerService methods -- @Override @@ -113,7 +154,7 @@ default Class> getPluginType() { } @Override - default Class getType() { - return String.class; + default Class getType() { + return Location.class; } } diff --git a/src/main/java/org/scijava/io/RecentFileService.java b/src/main/java/org/scijava/io/RecentFileService.java index e7ab47cae..38c6385a1 100644 --- a/src/main/java/org/scijava/io/RecentFileService.java +++ b/src/main/java/org/scijava/io/RecentFileService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 new file mode 100644 index 000000000..89fffd060 --- /dev/null +++ b/src/main/java/org/scijava/io/TypedIOService.java @@ -0,0 +1,180 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.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; + +/** + * Interface for high-level data I/O: opening and saving data of a specific type. + * + * @author Curtis Rueden + * @author Deborah Schmidt + */ +public interface TypedIOService extends HandlerService>, + SciJavaService +{ + + /** + * Gets the most appropriate {@link IOPlugin} for opening data from the given + * location. + */ + default IOPlugin getOpener(final String source) { + try { + return getOpener(context().service(LocationService.class).resolve(source)); + } + catch (final URISyntaxException exc) { + return null; + } + } + + /** + * Gets the most appropriate {@link IOPlugin} for opening data from the given + * location. + */ + default IOPlugin getOpener(Location source) { + for (final IOPlugin handler : getInstances()) { + if (handler.supportsOpen(source)) return handler; + } + return null; + } + + /** + * Gets the most appropriate {@link IOPlugin} for saving data to the given + * location. + */ + default IOPlugin getSaver(final D data, final String destination) { + try { + return getSaver(data, context().service(LocationService.class).resolve(destination)); + } + catch (final URISyntaxException exc) { + return null; + } + } + + /** + * Gets the most appropriate {@link IOPlugin} for saving data to the given + * location. + */ + default IOPlugin getSaver(D data, Location destination) { + for (final IOPlugin handler : getInstances()) { + if (handler.supportsSave(data, destination)) { + return (IOPlugin) handler; + } + } + return null; + } + + /** + * Loads data from the given source. For extensibility, the nature of the + * source is left intentionally general, but two common examples include file + * paths and URLs. + *

+ * The opener to use is automatically determined based on available + * {@link IOPlugin}s; see {@link #getOpener(String)}. + *

+ * + * @param source The source (e.g., file path) from which to data should be + * loaded. + * @return An object representing the loaded data, or null if the source is + * not supported. + * @throws IOException if something goes wrong loading the data. + */ + D open(String source) throws IOException; + + /** + * Loads data from the given location. + *

+ * The opener to use is automatically determined based on available + * {@link IOPlugin}s; see {@link #getOpener(Location)}. + *

+ * + * @param source The location from which to data should be loaded. + * @return An object representing the loaded data, or null if the source is + * not supported. + * @throws IOException if something goes wrong loading the data. + */ + D open(Location source) throws IOException; + + /** + * Saves data to the given destination. The nature of the destination is left + * intentionally general, but the most common example is a file path. + *

+ * The saver to use is automatically determined based on available + * {@link IOPlugin}s; see {@link #getSaver(Object, String)}. + *

+ * + * @param data The data to be saved to the destination. + * @param destination The destination (e.g., file path) to which data should + * be saved. + * @throws IOException if something goes wrong saving the data. + */ + void save(D data, String destination) throws IOException; + + /** + * Saves data to the given location. + *

+ * The saver to use is automatically determined based on available + * {@link IOPlugin}s; see {@link #getSaver(Object, Location)}. + *

+ * + * @param data The data to be saved to the destination. + * @param destination The destination location to which data should be saved. + * @throws IOException if something goes wrong saving the data. + */ + void save(D data, Location destination) throws IOException; + + boolean canOpen(String source); + + boolean canOpen(Location source); + + boolean canSave(D data, String destination); + + boolean canSave(D data, Location destination); + + // -- HandlerService methods -- + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + default Class> getPluginType() { + return (Class) IOPlugin.class; + } + + @Override + default Class getType() { + return Location.class; + } +} diff --git a/src/main/java/org/scijava/io/console/OpenArgument.java b/src/main/java/org/scijava/io/console/OpenArgument.java index fa05f8afc..ab7aa259b 100644 --- a/src/main/java/org/scijava/io/console/OpenArgument.java +++ b/src/main/java/org/scijava/io/console/OpenArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 08ac7c0ef..b42d9fb0f 100644 --- a/src/main/java/org/scijava/io/event/DataOpenedEvent.java +++ b/src/main/java/org/scijava/io/event/DataOpenedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,22 +29,34 @@ package org.scijava.io.event; + +import org.scijava.io.location.FileLocation; +import org.scijava.io.location.Location; + /** - * An event indicating that data has been opened from a source. + * An event indicating that data has been opened from a location. * * @author Curtis Rueden */ public class DataOpenedEvent extends IOEvent { + public DataOpenedEvent(final Location location, final Object data) { + super(location, data); + } + + /** + * @deprecated use {@link #DataOpenedEvent(Location, Object)} instead + */ + @Deprecated public DataOpenedEvent(final String source, final Object data) { super(source, data); } - // -- DataOpenedEvent methods -- - - /** Gets the source from which data was opened. */ + /** + * @deprecated use {@link #getLocation} instead + */ + @Deprecated public String getSource() { 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 45691849f..74eaa8925 100644 --- a/src/main/java/org/scijava/io/event/DataSavedEvent.java +++ b/src/main/java/org/scijava/io/event/DataSavedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,6 +29,10 @@ package org.scijava.io.event; + +import org.scijava.io.location.FileLocation; +import org.scijava.io.location.Location; + /** * An event indicating that data has been saved to a destination. * @@ -39,15 +40,23 @@ */ public class DataSavedEvent extends IOEvent { - public DataSavedEvent(final String destination, final Object data) { + public DataSavedEvent(final Location destination, final Object data) { super(destination, data); } - // -- DataSavedEvent methods -- + /** + * @deprecated use {@link #DataSavedEvent(Location, Object)} instead + */ + @Deprecated + public DataSavedEvent(final String destination, final Object data) { + super(destination, data); + } - /** Gets the destination to which data was saved. */ + /** + * @deprecated use {@link #getLocation} instead + */ + @Deprecated public String getDestination() { 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 2c21cd076..e254fb0a8 100644 --- a/src/main/java/org/scijava/io/event/IOEvent.java +++ b/src/main/java/org/scijava/io/event/IOEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,7 +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. @@ -41,20 +43,41 @@ */ public abstract class IOEvent extends SciJavaEvent { - /** The data descriptor (source or destination). */ + /** 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; + /** + * @deprecated use {@link #IOEvent(Location, Object)} instead + */ + @Deprecated public IOEvent(final String descriptor, final Object data) { + this.location = null; this.descriptor = descriptor; this.data = data; } - /** Gets the data descriptor (source or destination). */ - public String getDescriptor() { - return descriptor; + 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() { + 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. */ @@ -66,7 +89,20 @@ public Object getData() { @Override public String toString() { - return super.toString() + "\n\tdescriptor = " + data + "\n\tdata = " + data; + return super.toString() + "\n\tlocation = " + location + "\n\tdata = " + + data; } + /** + * @deprecated use {@link #getLocation()} instead + */ + @Deprecated + public String getDescriptor() { + if (descriptor != null) return descriptor; + if (location instanceof FileLocation) { + final FileLocation fileLocation = (FileLocation) location; + return fileLocation.getFile().getAbsolutePath(); + } + 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 2d2258ab2..9a8a57973 100644 --- a/src/main/java/org/scijava/io/handle/AbstractDataHandle.java +++ b/src/main/java/org/scijava/io/handle/AbstractDataHandle.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,6 +41,13 @@ public abstract class AbstractDataHandle extends AbstractWrapperPlugin implements DataHandle { + private byte[] conversionBuffer = new byte[8]; + + @Override + public byte[] conversionBuffer() { + return conversionBuffer; + } + // -- Fields -- private ByteOrder order = ByteOrder.BIG_ENDIAN; diff --git a/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java b/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java index ae2a73451..a27fd185c 100644 --- a/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java +++ b/src/main/java/org/scijava/io/handle/AbstractHigherOrderHandle.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 diff --git a/src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java b/src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java new file mode 100644 index 000000000..a28428328 --- /dev/null +++ b/src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java @@ -0,0 +1,103 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.handle; + +import java.io.IOException; + +import org.scijava.io.location.Location; + +public abstract class AbstractSeekableStreamHandle extends + AbstractStreamHandle implements SeekableStreamHandle +{ + + private long jumpCutoff = 10000; + + @Override + public void seek(final long pos) throws IOException { + + // how much and which direction we have to jump + final long delta = pos - offset(); + + if (delta == 0) { + return; + // nothing to do + } + else if (delta > 0) { + // offset position is "downstream" + + // try to reconnect instead of linearly reading large chunks + if (recreatePossible() && delta > jumpCutoff) { + recreateStreamFromPos(pos); + } + else { + jump(delta); + } + + } + else { // delta < 0 + // need to recreate the stream + if (recreatePossible()) { + recreateStreamFromPos(pos); + } + else { + resetStream(); + jump(pos); + } + } + setOffset(pos); + } + + /** + * Recreates the internal input stream available through {@link #in()}, so + * that it starts from the specified position. + * + * @param pos + * @throws IOException + */ + protected abstract void recreateStreamFromPos(long pos) throws IOException; + + /** + * In some implementations of this class, the ability to recreate the stream + * depends on external factors (e.g. server support). This influences a + * + * @return if recreate is actually possible. + * @throws IOException + */ + protected abstract boolean recreatePossible() throws IOException; + + /** + * Sets the maximum of bytes which are read from the stream when seeking + * forward. Any larger number will result in a call to + * {@link #recreateStreamFromPos(long)}. + */ + protected void setJumpCutoff(long jumpCutoff) { + this.jumpCutoff = jumpCutoff; + } +} diff --git a/src/main/java/org/scijava/io/handle/AbstractStreamHandle.java b/src/main/java/org/scijava/io/handle/AbstractStreamHandle.java new file mode 100644 index 000000000..9660e9300 --- /dev/null +++ b/src/main/java/org/scijava/io/handle/AbstractStreamHandle.java @@ -0,0 +1,63 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.handle; + +import org.scijava.io.location.Location; + +/** + * Abstract base class for {@link StreamHandle} implementations. + * + * @author Curtis Rueden + * @author Melissa Linkert + */ +public abstract class AbstractStreamHandle extends + AbstractDataHandle implements StreamHandle +{ + + // -- Fields -- + + /** Current position within the stream(s). */ + private long offset; + + // -- StreamHandle methods -- + + @Override + public void setOffset(final long offset) { + this.offset = offset; + } + + // -- DataHandle methods -- + + @Override + public long offset() { + return offset; + } + +} diff --git a/src/main/java/org/scijava/io/handle/BytesHandle.java b/src/main/java/org/scijava/io/handle/BytesHandle.java index 7eb52dbd5..b4cc82b4f 100644 --- a/src/main/java/org/scijava/io/handle/BytesHandle.java +++ b/src/main/java/org/scijava/io/handle/BytesHandle.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -51,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 @@ -87,9 +92,13 @@ public void setLength(final long length) throws IOException { @Override public int read(final byte[] b, final int off, int len) throws IOException { + if(len == 0) return 0; if (offset + len > length()) { len = (int) (length() - offset); } + if(len == 0) { // EOF + return -1; + } bytes().getBytes(offset, b, off, len); offset += len; return len; diff --git a/src/main/java/org/scijava/io/handle/DataHandle.java b/src/main/java/org/scijava/io/handle/DataHandle.java index db48caeee..f5728f2cd 100644 --- a/src/main/java/org/scijava/io/handle/DataHandle.java +++ b/src/main/java/org/scijava/io/handle/DataHandle.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,6 +40,7 @@ import org.scijava.io.location.Location; import org.scijava.plugin.WrapperPlugin; +import org.scijava.util.Bytes; /** * A data handle is a plugin which provides both streaming and random @@ -249,6 +247,11 @@ default void setLittleEndian(final boolean little) { /** Sets the native encoding of the stream. */ void setEncoding(String encoding); + /** + * @return a 8 byte long buffer array used for type conversions + */ + byte[] conversionBuffer(); + /** Reads a string of arbitrary length, terminated by a null char. */ default String readCString() throws IOException { final String line = findString("\0"); @@ -344,10 +347,7 @@ default String findString(final boolean saveString, final int blockSize, final StringBuilder out = new StringBuilder(); final long startPos = offset(); long bytesDropped = 0; - final long inputLen = length(); - long maxLen = inputLen - startPos; - final boolean tooLong = saveString && maxLen > MAX_SEARCH_SIZE; - if (tooLong) maxLen = MAX_SEARCH_SIZE; + final long maxLen = saveString ? MAX_SEARCH_SIZE : Long.MAX_VALUE; boolean match = false; int maxTermLen = 0; for (final String term : terminators) { @@ -360,7 +360,10 @@ default String findString(final boolean saveString, final int blockSize, new DataHandleInputStream<>(this), getEncoding()); final char[] buf = new char[blockSize]; long loc = 0; - while (loc < maxLen && offset() < length() - 1) { + int r = 0; + + // NB: we need at least 2 bytes to read a char + while (loc < maxLen && ((r = in.read(buf, 0, blockSize)) > 1)) { // if we're not saving the string, drop any old, unnecessary output if (!saveString) { final int outLen = out.length(); @@ -372,16 +375,12 @@ default String findString(final boolean saveString, final int blockSize, bytesDropped += dropIndex; } } - - // read block from stream - final int r = in.read(buf, 0, blockSize); - if (r <= 0) throw new IOException("Cannot read from stream: " + r); - // append block to output out.append(buf, 0, r); // check output, returning smallest possible string - int min = Integer.MAX_VALUE, tagLen = 0; + int min = Integer.MAX_VALUE; + int tagLen = 0; for (final String t : terminators) { final int len = t.length(); final int start = (int) (loc - bytesDropped - len); @@ -409,7 +408,9 @@ default String findString(final boolean saveString, final int blockSize, } // no match - if (tooLong) throw new IOException("Maximum search length reached."); + if (loc > MAX_SEARCH_SIZE) { + throw new IOException("Maximum search length reached."); + } return saveString ? out.toString() : null; } @@ -514,18 +515,10 @@ default int readUnsignedByte() throws IOException { @Override default short readShort() throws IOException { - final int ch0; - final int ch1; - if (isBigEndian()) { - ch0 = read(); - ch1 = read(); - } - else { - ch1 = read(); - ch0 = read(); - } - if ((ch0 | ch1) < 0) throw new EOFException(); - return (short) ((ch0 << 8) + (ch1 << 0)); + final byte[] buf = conversionBuffer(); + final int read = read(buf, 0, 2); + if (read < 2) throw new EOFException(); + return Bytes.toShort(buf, isLittleEndian()); } @Override @@ -540,68 +533,20 @@ default char readChar() throws IOException { @Override default int readInt() throws IOException { - final int ch0; - final int ch1; - final int ch2; - final int ch3; - if (isBigEndian()) { - ch0 = read(); - ch1 = read(); - ch2 = read(); - ch3 = read(); - } - else { - ch3 = read(); - ch2 = read(); - ch1 = read(); - ch0 = read(); - } - if ((ch0 | ch1 | ch2 | ch3) < 0) throw new EOFException(); - return ((ch0 << 24) + (ch1 << 16) + (ch2 << 8) + (ch3 << 0)); + final byte[] buf = conversionBuffer(); + final int read = read(buf, 0, 4); + if (read < 4) throw new EOFException(); + return Bytes.toInt(buf, isLittleEndian()); } @Override default long readLong() throws IOException { - final int ch0; - final int ch1; - final int ch2; - final int ch3; - final int ch4; - final int ch5; - final int ch6; - final int ch7; - if (isBigEndian()) { - ch0 = read(); - ch1 = read(); - ch2 = read(); - ch3 = read(); - ch4 = read(); - ch5 = read(); - ch6 = read(); - ch7 = read(); - } - else { - ch7 = read(); - ch6 = read(); - ch5 = read(); - ch4 = read(); - ch3 = read(); - ch2 = read(); - ch1 = read(); - ch0 = read(); - } - if ((ch0 | ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7) < 0) { + final byte[] buf = conversionBuffer(); + final int read = read(buf, 0, 8); + if (read < 8) { throw new EOFException(); } - // TODO: Double check this inconsistent code. - return ((long) ch0 << 56) + // - ((long) (ch1 & 255) << 48) + // - ((long) (ch2 & 255) << 40) + // - ((long) (ch3 & 255) << 32) + // - ((long) (ch4 & 255) << 24) + // - ((ch5 & 255) << 16) + // - ((ch6 & 255) << 8) + // - ((ch7 & 255) << 0); + return Bytes.toLong(buf, isLittleEndian()); } @Override @@ -618,7 +563,7 @@ default double readDouble() throws IOException { default String readLine() throws IOException { // NB: Adapted from java.io.RandomAccessFile.readLine(). - final StringBuffer input = new StringBuffer(); + final StringBuilder input = new StringBuilder(); int c = -1; boolean eol = false; @@ -669,76 +614,42 @@ default void writeByte(final int v) throws IOException { @Override default void writeShort(final int v) throws IOException { - if (isBigEndian()) { - write((v >>> 8) & 0xFF); - write((v >>> 0) & 0xFF); - } - else { - write((v >>> 0) & 0xFF); - write((v >>> 8) & 0xFF); - } + final byte[] buf = conversionBuffer(); + Bytes.unpack(v, buf, 0, 2, isLittleEndian()); + write(buf, 0, 2); } @Override default void writeChar(final int v) throws IOException { - if (isBigEndian()) { - write((v >>> 8) & 0xFF); - write((v >>> 0) & 0xFF); - } - else { - write((v >>> 0) & 0xFF); - write((v >>> 8) & 0xFF); - } + writeShort(v); } @Override default void writeInt(final int v) throws IOException { - if (isBigEndian()) { - write((v >>> 24) & 0xFF); - write((v >>> 16) & 0xFF); - write((v >>> 8) & 0xFF); - write((v >>> 0) & 0xFF); - } - else { - write((v >>> 0) & 0xFF); - write((v >>> 8) & 0xFF); - write((v >>> 16) & 0xFF); - write((v >>> 24) & 0xFF); - } + final byte[] buf = conversionBuffer(); + Bytes.unpack(v, buf, 0, 4, isLittleEndian()); + write(buf, 0, 4); } @Override default void writeLong(final long v) throws IOException { - if (isBigEndian()) { - write((byte) (v >>> 56)); - write((byte) (v >>> 48)); - write((byte) (v >>> 40)); - write((byte) (v >>> 32)); - write((byte) (v >>> 24)); - write((byte) (v >>> 16)); - write((byte) (v >>> 8)); - write((byte) (v >>> 0)); - } - else { - write((byte) (v >>> 0)); - write((byte) (v >>> 8)); - write((byte) (v >>> 16)); - write((byte) (v >>> 24)); - write((byte) (v >>> 32)); - write((byte) (v >>> 40)); - write((byte) (v >>> 48)); - write((byte) (v >>> 56)); - } + final byte[] buf = conversionBuffer(); + Bytes.unpack(v, buf, 0, 8, isLittleEndian()); + write(buf, 0, 8); } @Override default void writeFloat(final float v) throws IOException { - writeInt(Float.floatToIntBits(v)); + final byte[] buf = conversionBuffer(); + Bytes.unpack(Float.floatToIntBits(v), buf, 0, 4, isLittleEndian()); + write(buf, 0, 4); } @Override default void writeDouble(final double v) throws IOException { - writeLong(Double.doubleToLongBits(v)); + final byte[] buf = conversionBuffer(); + Bytes.unpack(Double.doubleToLongBits(v), buf, 0, 8, isLittleEndian()); + write(buf, 0, 8); } @Override @@ -750,9 +661,7 @@ default void writeBytes(final String s) throws IOException { default void writeChars(final String s) throws IOException { final int len = s.length(); for (int i = 0; i < len; i++) { - final int v = s.charAt(i); - write((v >>> 8) & 0xFF); - write((v >>> 0) & 0xFF); + writeChar(s.charAt(i)); } } diff --git a/src/main/java/org/scijava/io/handle/DataHandleInputStream.java b/src/main/java/org/scijava/io/handle/DataHandleInputStream.java index d96cfed49..e37ef5948 100644 --- a/src/main/java/org/scijava/io/handle/DataHandleInputStream.java +++ b/src/main/java/org/scijava/io/handle/DataHandleInputStream.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8291985ba..510a68e51 100644 --- a/src/main/java/org/scijava/io/handle/DataHandleOutputStream.java +++ b/src/main/java/org/scijava/io/handle/DataHandleOutputStream.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f2a24ba6d..16782658f 100644 --- a/src/main/java/org/scijava/io/handle/DataHandleService.java +++ b/src/main/java/org/scijava/io/handle/DataHandleService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,7 +30,6 @@ package org.scijava.io.handle; import java.io.IOException; -import java.util.Objects; import org.scijava.io.IOService; import org.scijava.io.location.Location; @@ -72,12 +68,13 @@ default Class getType() { * * @param location the location to test * @return The result of {@link DataHandle#exists()} on a newly created handle - * on this location - * @throws IOException + * on this location. Also returns {@code false} if the handle can not + * be created. + * @throws IOException if the creation of the handle fails exceptionally */ default boolean exists(final Location location) throws IOException { try (DataHandle handle = create(location)) { - return handle.exists(); + return handle == null ? false : handle.exists(); } } @@ -86,18 +83,22 @@ default boolean exists(final Location location) throws IOException { * reading. * * @param handle the handle to wrap + * @return The handle wrapped in a read-only buffer, or {@code null} if the + * input handle is {@code null} * @see ReadBufferDataHandle#ReadBufferDataHandle(DataHandle) */ default DataHandle readBuffer(final DataHandle handle) { - Objects.nonNull(handle); - return new ReadBufferDataHandle(handle); + return handle == null ? null : new ReadBufferDataHandle(handle); } /** * Creates a {@link DataHandle} on the provided {@link Location} wrapped in a * read-only buffer for accelerated reading. * - * @param location the handle to wrap + * @param location the Location to create a buffered handle on. + * @return A {@link DataHandle} on the provided location wrapped in a + * read-only buffer, or {@code null} if no handle could be created for + * the location. * @see ReadBufferDataHandle#ReadBufferDataHandle(DataHandle) */ default DataHandle readBuffer(final Location location) { @@ -110,10 +111,11 @@ default DataHandle readBuffer(final Location location) { * accelerated writing. * * @param handle the handle to wrap + * @return the handle wrapped in a write-only buffer or {@code null} if the + * provided handle is {@code null} * @see WriteBufferDataHandle#WriteBufferDataHandle(DataHandle) */ default DataHandle writeBuffer(final DataHandle handle) { - Objects.nonNull(handle); - return new WriteBufferDataHandle(handle); + return handle == null ? null : new WriteBufferDataHandle(handle); } } diff --git a/src/main/java/org/scijava/io/handle/DataHandles.java b/src/main/java/org/scijava/io/handle/DataHandles.java index 9bed1a516..abdcc0afb 100644 --- a/src/main/java/org/scijava/io/handle/DataHandles.java +++ b/src/main/java/org/scijava/io/handle/DataHandles.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 diff --git a/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java b/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java index b2bf44b98..e820ca6ac 100644 --- a/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java +++ b/src/main/java/org/scijava/io/handle/DefaultDataHandleService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2244c4692..bb9cd70ac 100644 --- a/src/main/java/org/scijava/io/handle/DummyHandle.java +++ b/src/main/java/org/scijava/io/handle/DummyHandle.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -51,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 db54d562f..dbaedd134 100644 --- a/src/main/java/org/scijava/io/handle/FileHandle.java +++ b/src/main/java/org/scijava/io/handle/FileHandle.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +29,11 @@ package org.scijava.io.handle; +import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Date; import org.scijava.io.location.FileLocation; @@ -53,16 +53,27 @@ public class FileHandle extends AbstractDataHandle { private RandomAccessFile raf; /** The mode of the {@link RandomAccessFile}. */ - private String mode = "rw"; + private String mode; /** True iff the {@link #close()} has already been called. */ private boolean closed; + // -- Constructors -- + + public FileHandle() { } + + public FileHandle(final FileLocation location) { + set(location); + } + // -- FileHandle methods -- - /** Gets the random access file object backing this FileHandle. */ + /** + * Gets the random access file object backing this FileHandle. If the + * underlying file does not exist yet, it will be created. + */ public RandomAccessFile getRandomAccessFile() throws IOException { - return raf(); + return writer(); } public String getMode() { @@ -101,200 +112,162 @@ public Date lastModified() { @Override public long offset() throws IOException { - return raf().getFilePointer(); + return exists() ? reader().getFilePointer() : 0; } @Override public long length() throws IOException { - return exists() ? raf().length() : -1; + return exists() ? reader().length() : -1; } @Override public void setLength(final long length) throws IOException { - raf().setLength(length); + writer().setLength(length); } @Override public int read() throws IOException { - return raf().read(); + return reader().read(); } @Override public int read(final byte[] b) throws IOException { - return raf().read(b); + return reader().read(b); } @Override public int read(final byte[] b, final int off, final int len) throws IOException { - return raf().read(b, off, len); + return reader().read(b, off, len); } @Override public void seek(final long pos) throws IOException { - raf().seek(pos); + if (isWritable()) { + writer().seek(pos); + } + else { + reader().seek(pos); + } } // -- DataInput methods -- @Override public boolean readBoolean() throws IOException { - return raf().readBoolean(); + return reader().readBoolean(); } @Override public byte readByte() throws IOException { - return raf().readByte(); - } - - @Override - public char readChar() throws IOException { - return raf().readChar(); - } - - @Override - public double readDouble() throws IOException { - return raf().readDouble(); - } - - @Override - public float readFloat() throws IOException { - return raf().readFloat(); + return reader().readByte(); } @Override public void readFully(final byte[] b) throws IOException { - raf().readFully(b); + reader().readFully(b); } @Override public void readFully(final byte[] b, final int off, final int len) throws IOException { - raf().readFully(b, off, len); - } - - @Override - public int readInt() throws IOException { - return raf().readInt(); + reader().readFully(b, off, len); } @Override public String readLine() throws IOException { - return raf().readLine(); - } - - @Override - public long readLong() throws IOException { - return raf().readLong(); - } - - @Override - public short readShort() throws IOException { - return raf().readShort(); + return reader().readLine(); } @Override public int readUnsignedByte() throws IOException { - return raf().readUnsignedByte(); - } - - @Override - public int readUnsignedShort() throws IOException { - return raf().readUnsignedShort(); + return reader().readUnsignedByte(); } @Override public String readUTF() throws IOException { - return raf().readUTF(); + return reader().readUTF(); } @Override public int skipBytes(final int n) throws IOException { - return raf().skipBytes(n); + return reader().skipBytes(n); } // -- DataOutput methods -- @Override public void write(final byte[] b) throws IOException { - raf().write(b); + writer().write(b); } @Override public void write(final byte[] b, final int off, final int len) throws IOException { - raf().write(b, off, len); + writer().write(b, off, len); } @Override public void write(final int b) throws IOException { - raf().write(b); + writer().write(b); } @Override public void writeBoolean(final boolean v) throws IOException { - raf().writeBoolean(v); + writer().writeBoolean(v); } @Override public void writeByte(final int v) throws IOException { - raf().writeByte(v); + writer().writeByte(v); } @Override public void writeBytes(final String s) throws IOException { - raf().writeBytes(s); - } - - @Override - public void writeChar(final int v) throws IOException { - raf().writeChar(v); + writer().writeBytes(s); } @Override public void writeChars(final String s) throws IOException { - raf().writeChars(s); + writer().writeChars(s); } @Override - public void writeDouble(final double v) throws IOException { - raf().writeDouble(v); + public void writeUTF(final String str) throws IOException { + writer().writeUTF(str); } - @Override - public void writeFloat(final float v) throws IOException { - raf().writeFloat(v); - } + // -- Closeable methods -- @Override - public void writeInt(final int v) throws IOException { - raf().writeInt(v); + public synchronized void close() throws IOException { + if (raf != null) raf.close(); + closed = true; } - @Override - public void writeLong(final long v) throws IOException { - raf().writeLong(v); - } + // -- WrapperPlugin methods -- @Override - public void writeShort(final int v) throws IOException { - raf().writeShort(v); - } + public void set(FileLocation loc) { + super.set(loc); - @Override - public void writeUTF(final String str) throws IOException { - raf().writeUTF(str); - } - - // -- Closeable methods -- - - @Override - public synchronized void close() throws IOException { - if (raf != null) raf().close(); - closed = true; + // Infer the initial mode based on file existence + permissions. + final File file = loc.getFile(); + String mode; + if (file.exists()) { + final Path path = loc.getFile().toPath(); + mode = ""; + if (Files.isReadable(path)) mode += "r"; + if (Files.isWritable(path)) mode += "w"; + } + else { + // Non-existent file; assume the intent is to create it. + mode = "rw"; + } + setMode(mode); } // -- Typed methods -- @@ -306,12 +279,47 @@ public Class getType() { // -- Helper methods -- - private RandomAccessFile raf() throws IOException { - if (raf == null) initRAF(); + /** + * Access method for the internal {@link RandomAccessFile}, that succeeds + * independently of the underlying file existing on disk. This allows us to + * create a new file for writing. + * + * @return the internal {@link RandomAccessFile} creating a new file on disk + * if needed. + * @throws IOException if the {@link RandomAccessFile} could not be created. + */ + private RandomAccessFile writer() throws IOException { + if (raf == null) initRAF(true); + return raf; + } + + /** + * Access method for the internal {@link RandomAccessFile}, that only succeeds + * if the underlying file exists on disk. This prevents accidental creation of + * an empty file when calling read operations on a non-existent file. + * + * @return the internal {@link RandomAccessFile}. + * @throws IOException if the {@link RandomAccessFile} could not be created, + * or the backing file does not exists. + */ + private RandomAccessFile reader() throws IOException { + if (raf == null) initRAF(false); return raf; } - private synchronized void initRAF() throws IOException { + /** + * Initializes the {@link RandomAccessFile}. + * + * @param create whether to create the {@link RandomAccessFile} if the + * underlying file does not exist yet. + * @throws IOException if the {@link RandomAccessFile} could not be created, + * or the backing file does not exist and the {@code create} + * parameter was set to {@code false}. + */ + private synchronized void initRAF(final boolean create) throws IOException { + if (!create && !exists()) { + throw new IOException("Trying to read from non-existent file!"); + } if (closed) throw new IOException("Handle already closed"); if (raf != null) return; raf = new RandomAccessFile(get().getFile(), getMode()); diff --git a/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java b/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java index b54ebe950..af306b73b 100644 --- a/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java +++ b/src/main/java/org/scijava/io/handle/ReadBufferDataHandle.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 @@ -47,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; @@ -58,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; @@ -70,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); } @@ -83,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); } @@ -97,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; @@ -167,7 +170,17 @@ private byte[] readPage(final int pageID, final int slotID) throws IOException { if (handle().offset() != startOfPage) { handle().seek(startOfPage); } - handle().read(page); + + // NB: we read repeatedly until the page is full or EOF is reached + // handle().read(..) might read less bytes than requested + int off = 0; + while (off < pageSize) { + final int read = handle().read(page, off, pageSize - off); + if (read == -1) { // EOF + break; + } + off += read; + } return page; } @@ -175,7 +188,7 @@ private byte[] readPage(final int pageID, final int slotID) throws IOException { * Calculates the offset in the current page for the given global offset */ private int globalToLocalOffset(final long off) { - return (int) off % pageSize; + return (int) (off % pageSize); } @Override @@ -183,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 @@ -204,9 +223,9 @@ public int read(final byte[] b, final int targetOffset, final int len) // calculate local offsets final int pageOffset = globalToLocalOffset(offset); int localLength = pageSize - pageOffset; - if (read + localLength > readLength) { - localLength = readLength - read; - } + localLength = Math.min(localLength, readLength - read); + localLength = Math.min(localLength, b.length - localTargetOff); + if (localLength == 0) break; // we've read all we can // copy the data System.arraycopy(currentPage, pageOffset, b, localTargetOff, localLength); @@ -274,7 +293,7 @@ private class LRUReplacementStrategy { public LRUReplacementStrategy(final int numSlots) { queue = new ArrayDeque<>(numSlots); - // fill the que + // fill the queue for (int i = 0; i < numSlots; i++) { queue.add(i); } @@ -288,12 +307,12 @@ public LRUReplacementStrategy(final int numSlots) { * the id of the slot that has been accessed */ public void accessed(final int slotID) { - // put accessed element to the end of the que + // put accessed element to the end of the queue queue.remove(slotID); queue.add(slotID); } - public int pickVictim(final int pageID) { + public int pickVictim(@SuppressWarnings("unused") final int pageID) { return queue.peek(); } } diff --git a/src/main/java/org/scijava/io/handle/ResettableStreamHandle.java b/src/main/java/org/scijava/io/handle/ResettableStreamHandle.java new file mode 100644 index 000000000..c202ad53d --- /dev/null +++ b/src/main/java/org/scijava/io/handle/ResettableStreamHandle.java @@ -0,0 +1,70 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.handle; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.scijava.io.location.Location; + +/** + * A {@link DataHandle} backed by an {@link InputStream} and/or + * {@link OutputStream}. Supports resetting the handle to the start of the + * internal stream(s). + */ +public interface ResettableStreamHandle extends + StreamHandle +{ + + @Override + default void seek(final long pos) throws IOException { + final long off = offset(); + if (pos == off) return; // nothing to do + if (pos > off) { + // jump from the current offset + jump(pos - off); + } + else { + // jump from the beginning of the stream + resetStream(); + jump(pos); + } + setOffset(pos); + } + + /** + * Resets the stream to its start. + * + * @throws IOException If something goes wrong with the reset + */ + @Override + void resetStream() throws IOException; +} diff --git a/src/main/java/org/scijava/io/handle/SeekableStreamHandle.java b/src/main/java/org/scijava/io/handle/SeekableStreamHandle.java new file mode 100644 index 000000000..bf517df16 --- /dev/null +++ b/src/main/java/org/scijava/io/handle/SeekableStreamHandle.java @@ -0,0 +1,51 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.handle; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.scijava.io.location.Location; + +/** + * A {@link DataHandle} backed by an {@link InputStream} and/or + * {@link OutputStream}. Supports seeking to an arbitrary position within the + * stream. + * + * @author Gabriel Einsdorf + */ +public interface SeekableStreamHandle extends + ResettableStreamHandle +{ + + @Override + void seek(long pos) throws IOException; +} diff --git a/src/main/java/org/scijava/io/handle/StreamHandle.java b/src/main/java/org/scijava/io/handle/StreamHandle.java new file mode 100644 index 000000000..f134315cb --- /dev/null +++ b/src/main/java/org/scijava/io/handle/StreamHandle.java @@ -0,0 +1,190 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.handle; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.scijava.io.location.Location; + +/** + * A {@link DataHandle} backed by an {@link InputStream} and/or + * {@link OutputStream}. + * + * @author Curtis Rueden + * @author Melissa Linkert + * @author Gabriel Einsdorf + */ +public interface StreamHandle extends DataHandle { + + // -- StreamHandle methods -- + + /** + * Gets an input stream for reading data, positioned at the current offset. + * + * @return the appropriate input stream, or null if the handle is write-only. + * @throws IOException + */ + InputStream in() throws IOException; + + /** + * Gets an output stream for writing data, positioned at the current offset. + * + * @return the appropriate output stream, or null if the handle is read-only. + */ + OutputStream out() throws IOException; + + /** + * Sets the offset of the handle to the given position. + *

+ * This method is intended to be called only in conjunction with reading from + * the input stream, or writing to the output stream. Otherwise, the contents + * may get out of sync. + *

+ */ + void setOffset(long offset); + + /** + * Increments the handle's offset by the given amount. + *

+ * This method is intended to be called only in conjunction with reading from + * the input stream, or writing to the output stream. Otherwise, the contents + * may get out of sync. + *

+ */ + default void advance(final long bytes) throws IOException { + setOffset(offset() + bytes); + } + + // -- DataHandle methods -- + + @Override + default void seek(final long pos) throws IOException { + if (pos == offset()) return; + if (pos > offset()) { + jump(pos - offset()); + } + else { + throw new UnsupportedOperationException( + "Can't seek backwards through this StreamHandle"); + } + } + + /** + * Resets the stream to its start. + * + * @throws IOException If something goes wrong with the reset + */ + void resetStream() throws IOException; + + default void jump(final long n) throws IOException, EOFException { + long remain = n; + while (remain > 0) { + final long r = in().skip(remain); + if (r < 0) throw new EOFException(); + remain -= r; + } + } + + @Override + default void ensureReadable(final long count) throws IOException { + if (in() == null) throw new IOException("This handle is write-only."); + DataHandle.super.ensureReadable(count); + } + + @Override + default boolean ensureWritable(final long count) throws IOException { + if (out() == null) throw new IOException("This handle is read-only."); + return DataHandle.super.ensureWritable(count); + } + + @Override + default int read() throws IOException { + ensureReadable(0); + final int v = in().read(); + if (v >= 0) advance(1); + return v; + } + + @Override + default byte readByte() throws IOException { + int ch = this.read(); + if (ch < 0) throw new EOFException(); + return (byte) (ch); + } + + @Override + default int read(final byte[] b, final int off, final int len) + throws IOException + { + final int n = in().read(b, off, len); + if (n >= 0) advance(n); + return n; + } + + // -- DataOutput methods -- + + @Override + default void write(final int v) throws IOException { + ensureWritable(1); + out().write(v); + advance(1); + } + + @Override + default void writeByte(int v) throws IOException { + write(v); + } + + @Override + default void write(final byte[] b, final int off, final int len) + throws IOException + { + ensureWritable(len); + out().write(b, off, len); + advance(len); + } + + // -- Closeable methods -- + + @Override + default void close() throws IOException { + // TODO: Double check this logic. + try (final InputStream in = in()) { + if (in != null) in.close(); + } + try (final OutputStream out = out()) { + if (out != null) out.close(); + } + } + +} diff --git a/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java b/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java index 41c1603a8..44c8b5064 100644 --- a/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java +++ b/src/main/java/org/scijava/io/handle/WriteBufferDataHandle.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 diff --git a/src/main/java/org/scijava/io/location/AbstractLocation.java b/src/main/java/org/scijava/io/location/AbstractLocation.java index 3d614d162..045d6fc37 100644 --- a/src/main/java/org/scijava/io/location/AbstractLocation.java +++ b/src/main/java/org/scijava/io/location/AbstractLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,6 +29,7 @@ package org.scijava.io.location; +import java.net.URI; import java.util.Objects; /** @@ -58,4 +56,13 @@ public boolean equals(final Object obj) { return Objects.equals(getURI(), other.getURI()); } + @Override + public String toString() { + final String prefix = getClass().getSimpleName() + ":"; + final URI uri = getURI(); + if (uri != null) return prefix + uri; + final String name = getName(); + if (name != null) return prefix + name; + return prefix + defaultName(); + } } diff --git a/src/main/java/org/scijava/io/location/AbstractLocationResolver.java b/src/main/java/org/scijava/io/location/AbstractLocationResolver.java index 3ab3c8e75..675a4c775 100644 --- a/src/main/java/org/scijava/io/location/AbstractLocationResolver.java +++ b/src/main/java/org/scijava/io/location/AbstractLocationResolver.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5a5873ed3..2d211157f 100644 --- a/src/main/java/org/scijava/io/location/AbstractRemoteLocation.java +++ b/src/main/java/org/scijava/io/location/AbstractRemoteLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cd3daaccd..234d2c88b 100644 --- a/src/main/java/org/scijava/io/location/BrowsableLocation.java +++ b/src/main/java/org/scijava/io/location/BrowsableLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 43c08e659..d16e83c69 100644 --- a/src/main/java/org/scijava/io/location/BytesLocation.java +++ b/src/main/java/org/scijava/io/location/BytesLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,7 +31,6 @@ import org.scijava.io.ByteArrayByteBank; import org.scijava.io.ByteBank; -import org.scijava.io.handle.DataHandle; import org.scijava.util.ByteArray; /** @@ -47,6 +43,8 @@ public class BytesLocation extends AbstractLocation { private final ByteBank bytes; + private final String name; + /** * Creates a {@link BytesLocation} backed by the specified * {@link ByteBank}. @@ -54,7 +52,18 @@ public class BytesLocation extends AbstractLocation { * @param bytes the {@link ByteBank} that will back this {@link Location} */ public BytesLocation(final ByteBank bytes) { + this(bytes, null); + } + + /** + * Creates a {@link BytesLocation} backed by the specified {@link ByteBank}. + * + * @param bytes the {@link ByteBank} that will back this {@link Location} + * @param name the name of this {@link Location} + */ + public BytesLocation(final ByteBank bytes, final String name) { this.bytes = bytes; + this.name = name; } /** @@ -63,7 +72,19 @@ public BytesLocation(final ByteBank bytes) { * can be used to avoid needing to grow the underlying {@link ByteBank}. */ public BytesLocation(final int initialCapacity) { + this(initialCapacity, null); + } + + /** + * Creates a {@link BytesLocation} backed by a {@link ByteArrayByteBank} with + * the specified initial capacity, but with a reported size of 0. This method + * can be used to avoid needing to grow the underlying {@link ByteBank}. + * + * @param name the name of this {@link Location} + */ + public BytesLocation(final int initialCapacity, final String name) { this.bytes = new ByteArrayByteBank(initialCapacity); + this.name = name; } /** @@ -71,7 +92,18 @@ public BytesLocation(final int initialCapacity) { * that wraps the specified {@link ByteArray}. */ public BytesLocation(final ByteArray bytes) { + this(bytes, null); + } + + /** + * Creates a {@link BytesLocation} backed by a {@link ByteArrayByteBank} that + * wraps the specified {@link ByteArray}. + * + * @param name the name of this Location. + */ + public BytesLocation(final ByteArray bytes, final String name) { this.bytes = new ByteArrayByteBank(bytes); + this.name = name; } /** @@ -81,7 +113,19 @@ public BytesLocation(final ByteArray bytes) { * @param bytes the array to wrap */ public BytesLocation(final byte[] bytes) { + this(bytes, null); + } + + /** + * Creates a {@link BytesLocation} backed by a {@link ByteArrayByteBank} which + * wraps the specified array. + * + * @param bytes the array to wrap + * @param name the name of this Location. + */ + public BytesLocation(final byte[] bytes, final String name) { this.bytes = new ByteArrayByteBank(bytes); + this.name = name; } /** @@ -92,11 +136,25 @@ public BytesLocation(final byte[] bytes) { * @param offset the offset in the bytes array to start copying from * @param length the number of bytes to copy, starting from the offset */ - public BytesLocation(final byte[] bytes, final int offset, - final int length) + public BytesLocation(final byte[] bytes, final int offset, final int length) { + this(bytes, offset, length, null); + } + + /** + * Creates a {@link BytesLocation} backed by a {@link ByteArrayByteBank} with + * the specified initial capacity and the provided data. + * + * @param bytes the bytes to copy into the new {@link BytesLocation} + * @param offset the offset in the bytes array to start copying from + * @param length the number of bytes to copy, starting from the offset + * @param name the name of this Location. + */ + public BytesLocation(final byte[] bytes, final int offset, final int length, + final String name) { this.bytes = new ByteArrayByteBank(length); this.bytes.setBytes(0l, bytes, offset, length); + this.name = name; } // -- BytesLocation methods -- @@ -106,6 +164,11 @@ public ByteBank getByteBank() { return bytes; } + @Override + public String getName() { + return name != null ? name : defaultName(); + } + // -- Object methods -- @Override diff --git a/src/main/java/org/scijava/io/location/DefaultLocationService.java b/src/main/java/org/scijava/io/location/DefaultLocationService.java index d8c3c037d..d4ea0845a 100644 --- a/src/main/java/org/scijava/io/location/DefaultLocationService.java +++ b/src/main/java/org/scijava/io/location/DefaultLocationService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,8 +30,6 @@ package org.scijava.io.location; import java.net.URI; -import java.util.HashMap; -import java.util.Map; import org.scijava.plugin.AbstractHandlerService; import org.scijava.plugin.Plugin; @@ -50,11 +45,5 @@ public class DefaultLocationService extends AbstractHandlerService implements LocationService { - - private final Map resolvers = new HashMap<>(); - - @Override - public LocationResolver getResolver(final URI uri) { - return resolvers.computeIfAbsent(uri.getScheme(), u -> getHandler(uri)); - } + // NB: No implementation needed. } diff --git a/src/main/java/org/scijava/io/location/DummyLocation.java b/src/main/java/org/scijava/io/location/DummyLocation.java index 564305b0b..f1e2b4f64 100644 --- a/src/main/java/org/scijava/io/location/DummyLocation.java +++ b/src/main/java/org/scijava/io/location/DummyLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7790ae4ec..195389196 100644 --- a/src/main/java/org/scijava/io/location/FileLocation.java +++ b/src/main/java/org/scijava/io/location/FileLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,6 +34,7 @@ import java.net.URI; import java.util.Collections; import java.util.HashSet; +import java.util.Objects; import java.util.Set; /** @@ -52,6 +50,7 @@ public class FileLocation extends AbstractLocation implements private final File file; public FileLocation(final File file) { + Objects.requireNonNull(file); this.file = file; } diff --git a/src/main/java/org/scijava/io/location/FileLocationResolver.java b/src/main/java/org/scijava/io/location/FileLocationResolver.java index b40f0f13e..67c57420c 100644 --- a/src/main/java/org/scijava/io/location/FileLocationResolver.java +++ b/src/main/java/org/scijava/io/location/FileLocationResolver.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 bec21e813..1d2510c54 100644 --- a/src/main/java/org/scijava/io/location/Location.java +++ b/src/main/java/org/scijava/io/location/Location.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6e71f617c..0f325a002 100644 --- a/src/main/java/org/scijava/io/location/LocationResolver.java +++ b/src/main/java/org/scijava/io/location/LocationResolver.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 193e03929..1af4e1e26 100644 --- a/src/main/java/org/scijava/io/location/LocationService.java +++ b/src/main/java/org/scijava/io/location/LocationService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,6 +29,7 @@ package org.scijava.io.location; +import java.io.File; import java.net.URI; import java.net.URISyntaxException; @@ -49,40 +47,48 @@ public interface LocationService extends HandlerService, { /** - * Turns the given string into an {@link URI}, then resolves it to a - * {@link Location} - * - * @param uri the uri to resolve + * Turns the given string into a {@link URI}, then resolves it to a + * {@link Location}. + * + * @param uriString the uri to resolve * @return the resolved {@link Location} * @throws URISyntaxException if the URI is malformed */ - default Location resolve(final String uri) throws URISyntaxException { - return resolve(new URI(uri)); + default Location resolve(final String uriString) throws URISyntaxException { + try { + 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()); } /** - * Resolves the given {@link URI} to a location. - * + * Resolves the given {@link URI} to a location. If the {@code scheme} part of + * the URI is {@code null} the path component is resolved as a local file. + * * @param uri the uri to resolve * @return the resolved {@link Location} or null if no resolver * could be found. * @throws URISyntaxException if the URI is malformed */ - default Location resolve(final URI uri) throws URISyntaxException { + default Location resolve(URI uri) throws URISyntaxException { + if (uri.getScheme() == null) { // Fallback for local files + uri = new File(uri.getPath()).toURI(); + } final LocationResolver resolver = getResolver(uri); return resolver != null ? resolver.resolve(uri) : null; } - /** - * Returns a {@link LocationResolver} capable of resolving URL like the one - * provided to this method. Allows faster repeated resolving of similar URIs - * without going through this service. - * - * @param uri the uri - * @return the {@link LocationResolver} for this uri type, or - * null if no resolver could be found. - */ - LocationResolver getResolver(URI uri); + /** @deprecated Use {@link #getHandler} instead. */ + @Deprecated + default LocationResolver getResolver(URI uri) { + return getHandler(uri); + } // -- PTService methods -- diff --git a/src/main/java/org/scijava/io/location/RemoteLocation.java b/src/main/java/org/scijava/io/location/RemoteLocation.java index 94cc2155b..a39282b4f 100644 --- a/src/main/java/org/scijava/io/location/RemoteLocation.java +++ b/src/main/java/org/scijava/io/location/RemoteLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8ea6531cc..0e5165a4a 100644 --- a/src/main/java/org/scijava/io/location/URILocation.java +++ b/src/main/java/org/scijava/io/location/URILocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -115,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 14b96a4b0..73c4781f2 100644 --- a/src/main/java/org/scijava/io/location/URLLocation.java +++ b/src/main/java/org/scijava/io/location/URLLocation.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -61,7 +58,7 @@ public URL getURL() { /** * Gets the associated {@link URI}, or null if this URL is not formatted - * strictly according to to RFC2396 and cannot be converted to a URI. + * strictly according to RFC2396 and cannot be converted to a URI. */ @Override public URI getURI() { diff --git a/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java b/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java index a159185a8..99588b672 100644 --- a/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java +++ b/src/main/java/org/scijava/io/nio/ByteBufferByteBank.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 29785ec49..6e0ef72da 100644 --- a/src/main/java/org/scijava/io/nio/DefaultNIOService.java +++ b/src/main/java/org/scijava/io/nio/DefaultNIOService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1d67b0a66..ea5c6696c 100644 --- a/src/main/java/org/scijava/io/nio/NIOService.java +++ b/src/main/java/org/scijava/io/nio/NIOService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -63,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 09038ea6b..1227ea134 100644 --- a/src/main/java/org/scijava/log/AbstractLogService.java +++ b/src/main/java/org/scijava/log/AbstractLogService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -107,7 +104,7 @@ public LogSource getSource() { @Override public int getLevel() { if (classAndPackageLevels.isEmpty()) return currentLevel; - return getLevelForClass(CallingClassUtils.getCallingClass().getName(), + return getLevelForClass(CallingClassUtils.getCallingClassName(), currentLevel); } diff --git a/src/main/java/org/scijava/log/CallingClassUtils.java b/src/main/java/org/scijava/log/CallingClassUtils.java index c885a7ac8..34a52d894 100644 --- a/src/main/java/org/scijava/log/CallingClassUtils.java +++ b/src/main/java/org/scijava/log/CallingClassUtils.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 @@ -31,6 +29,8 @@ package org.scijava.log; +import org.scijava.Context; + /** * Utility class for getting the calling class of a method. * @@ -45,12 +45,44 @@ private CallingClassUtils() { } /** + * Inspects the stack trace to return the name of the class that calls + * this method, but ignores every class annotated with @IgnoreAsCallingClass. + *

+ * If every class on the stack trace is annotated, then the class at the + * root of the stack trace is returned. + */ + public static String getCallingClassName() { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for (int i = 1; i < stackTrace.length - 2; i++) { + String className = stackTrace[i].getClassName(); + if (!hasIgnoreAsCallingClassAnnotation(className)) return className; + } + return stackTrace[stackTrace.length - 1].getClassName(); + } + + private static boolean hasIgnoreAsCallingClassAnnotation(String className) { + try { + Class< ? > clazz = Context.getClassLoader().loadClass(className); + return clazz.isAnnotationPresent(IgnoreAsCallingClass.class); + } + catch (ClassNotFoundException ignore) { + return false; + } + } + + /** + * @deprecated Use {@link #getCallingClassName()} instead. + * + * Warning: This method throws a IllegalStateException as soon as it comes + * across a class that can't be loaded with the default class loader. + * * Inspects the stack trace to return the class that calls this method, but * ignores every class annotated with @IgnoreAsCallingClass. * * @throws IllegalStateException if every method on the stack, is in a class * annotated with @IgnoreAsCallingClass. */ + @Deprecated public static Class getCallingClass() { try { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); diff --git a/src/main/java/org/scijava/log/DefaultLogger.java b/src/main/java/org/scijava/log/DefaultLogger.java index 7e5fb7a00..9f148f647 100644 --- a/src/main/java/org/scijava/log/DefaultLogger.java +++ b/src/main/java/org/scijava/log/DefaultLogger.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 diff --git a/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java b/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java index 526b27331..1d3e9704e 100644 --- a/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java +++ b/src/main/java/org/scijava/log/DefaultUncaughtExceptionHandler.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 de7c2f974..faa0da4d8 100644 --- a/src/main/java/org/scijava/log/IgnoreAsCallingClass.java +++ b/src/main/java/org/scijava/log/IgnoreAsCallingClass.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 @@ -36,7 +34,7 @@ /** * Classes annotated with {@link IgnoreAsCallingClass} are ignored by - * {@link CallingClassUtils#getCallingClass()}. + * {@link CallingClassUtils#getCallingClassName()}. * * @author Matthias Arzt */ diff --git a/src/main/java/org/scijava/log/LogLevel.java b/src/main/java/org/scijava/log/LogLevel.java index e38b85e80..cc36aba55 100644 --- a/src/main/java/org/scijava/log/LogLevel.java +++ b/src/main/java/org/scijava/log/LogLevel.java @@ -2,9 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 88a1a63d4..fabbfa435 100644 --- a/src/main/java/org/scijava/log/LogListener.java +++ b/src/main/java/org/scijava/log/LogListener.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 diff --git a/src/main/java/org/scijava/log/LogMessage.java b/src/main/java/org/scijava/log/LogMessage.java index 6eee6e8cf..fde5af3b9 100644 --- a/src/main/java/org/scijava/log/LogMessage.java +++ b/src/main/java/org/scijava/log/LogMessage.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 @@ -132,7 +130,7 @@ public String toString() { final StringWriter sw = new StringWriter(); final PrintWriter printer = new PrintWriter(sw); printer.print("[" + LogLevel.prefix(level()) + "] "); - printer.println(text()); + if(text() != null) printer.println(text()); if (throwable() != null) { throwable().printStackTrace(printer); } diff --git a/src/main/java/org/scijava/log/LogService.java b/src/main/java/org/scijava/log/LogService.java index ef79590bc..7d7eac93f 100644 --- a/src/main/java/org/scijava/log/LogService.java +++ b/src/main/java/org/scijava/log/LogService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ad7bbacf3..4338e3a8a 100644 --- a/src/main/java/org/scijava/log/LogSource.java +++ b/src/main/java/org/scijava/log/LogSource.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 diff --git a/src/main/java/org/scijava/log/Logged.java b/src/main/java/org/scijava/log/Logged.java index fab36ba9f..7f44f3f75 100644 --- a/src/main/java/org/scijava/log/Logged.java +++ b/src/main/java/org/scijava/log/Logged.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 bc0f3203e..8806a1dde 100644 --- a/src/main/java/org/scijava/log/Logger.java +++ b/src/main/java/org/scijava/log/Logger.java @@ -2,9 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e59a85a06..184f11d52 100644 --- a/src/main/java/org/scijava/log/StderrLogService.java +++ b/src/main/java/org/scijava/log/StderrLogService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f706fbefb..faffc2546 100644 --- a/src/main/java/org/scijava/main/DefaultMainService.java +++ b/src/main/java/org/scijava/main/DefaultMainService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c4a4ac2d0..ac21af8f0 100644 --- a/src/main/java/org/scijava/main/MainService.java +++ b/src/main/java/org/scijava/main/MainService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 793fdce2c..f9139ff6c 100644 --- a/src/main/java/org/scijava/main/console/MainArgument.java +++ b/src/main/java/org/scijava/main/console/MainArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2e86b3b5c..627e8ece3 100644 --- a/src/main/java/org/scijava/main/run/MainCodeRunner.java +++ b/src/main/java/org/scijava/main/run/MainCodeRunner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b88dd28db..94dd1f596 100644 --- a/src/main/java/org/scijava/menu/AbstractMenuCreator.java +++ b/src/main/java/org/scijava/menu/AbstractMenuCreator.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e231a8819..37863c869 100644 --- a/src/main/java/org/scijava/menu/DefaultMenuService.java +++ b/src/main/java/org/scijava/menu/DefaultMenuService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -79,25 +76,22 @@ public ShadowMenu getMenu(final String menuRoot) { // -- Event handlers -- @EventHandler - protected void onEvent(final ModulesAddedEvent event) { - if (rootMenus == null) { - // add *all* known modules, which includes the ones given here - rootMenus(); - return; - } - // data structure already exists; add *these* modules only + protected synchronized void onEvent(final ModulesAddedEvent event) { + if (rootMenus == null) return; // menus not yet initialized addModules(event.getItems()); } @EventHandler - protected void onEvent(final ModulesRemovedEvent event) { + protected synchronized void onEvent(final ModulesRemovedEvent event) { + if (rootMenus == null) return; // menus not yet initialized for (final ShadowMenu menu : rootMenus().values()) { menu.removeAll(event.getItems()); } } @EventHandler - protected void onEvent(final ModulesUpdatedEvent event) { + protected synchronized void onEvent(final ModulesUpdatedEvent event) { + if (rootMenus == null) return; // menus not yet initialized for (final ShadowMenu menu : rootMenus().values()) { menu.updateAll(event.getItems()); } @@ -165,9 +159,7 @@ private synchronized void addModules(final Collection items, *

*/ private HashMap rootMenus() { - if (rootMenus == null) { - initRootMenus(); - } + if (rootMenus == null) initRootMenus(); return rootMenus; } diff --git a/src/main/java/org/scijava/menu/MenuConstants.java b/src/main/java/org/scijava/menu/MenuConstants.java index 680b52f86..c68b5171c 100644 --- a/src/main/java/org/scijava/menu/MenuConstants.java +++ b/src/main/java/org/scijava/menu/MenuConstants.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ebda18708..571ea192e 100644 --- a/src/main/java/org/scijava/menu/MenuCreator.java +++ b/src/main/java/org/scijava/menu/MenuCreator.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 02747467d..8455284ac 100644 --- a/src/main/java/org/scijava/menu/MenuService.java +++ b/src/main/java/org/scijava/menu/MenuService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4a067692e..e0cecb326 100644 --- a/src/main/java/org/scijava/menu/ShadowMenu.java +++ b/src/main/java/org/scijava/menu/ShadowMenu.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -233,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; @@ -493,7 +497,7 @@ public T[] toArray(final T[] a) { // -- Helper methods -- private ShadowMenu addInternal(final ModuleInfo o) { - if (o.getMenuPath().isEmpty()) return null; // no menu + if (o.getMenuPath() == null || o.getMenuPath().isEmpty()) return null; // no menu return addChild(o, 0); } diff --git a/src/main/java/org/scijava/menu/ShadowMenuIterator.java b/src/main/java/org/scijava/menu/ShadowMenuIterator.java index e4ae4883c..45dfc836e 100644 --- a/src/main/java/org/scijava/menu/ShadowMenuIterator.java +++ b/src/main/java/org/scijava/menu/ShadowMenuIterator.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 220a8389f..c1e81f70e 100644 --- a/src/main/java/org/scijava/menu/event/MenuEvent.java +++ b/src/main/java/org/scijava/menu/event/MenuEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7474e77a1..796bd039b 100644 --- a/src/main/java/org/scijava/menu/event/MenusAddedEvent.java +++ b/src/main/java/org/scijava/menu/event/MenusAddedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c8fb8c1df..fe156cde6 100644 --- a/src/main/java/org/scijava/menu/event/MenusRemovedEvent.java +++ b/src/main/java/org/scijava/menu/event/MenusRemovedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 75ac1d5a0..01df28f33 100644 --- a/src/main/java/org/scijava/menu/event/MenusUpdatedEvent.java +++ b/src/main/java/org/scijava/menu/event/MenusUpdatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ca13bf3db..e6400f7cc 100644 --- a/src/main/java/org/scijava/module/AbstractModule.java +++ b/src/main/java/org/scijava/module/AbstractModule.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/AbstractModuleInfo.java b/src/main/java/org/scijava/module/AbstractModuleInfo.java index 7020f24ed..78747cacb 100644 --- a/src/main/java/org/scijava/module/AbstractModuleInfo.java +++ b/src/main/java/org/scijava/module/AbstractModuleInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3f881b944..ad9b863d2 100644 --- a/src/main/java/org/scijava/module/AbstractModuleItem.java +++ b/src/main/java/org/scijava/module/AbstractModuleItem.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/DefaultModuleService.java b/src/main/java/org/scijava/module/DefaultModuleService.java index 4cd4da238..b6d3fa025 100644 --- a/src/main/java/org/scijava/module/DefaultModuleService.java +++ b/src/main/java/org/scijava/module/DefaultModuleService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -77,7 +74,7 @@ public class DefaultModuleService extends AbstractService implements ModuleService { - @Parameter + @Parameter(required = false) private LogService log; @Parameter @@ -173,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; } @@ -254,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; } @@ -339,6 +336,16 @@ public T getDefaultValue(final ModuleItem item) { return null; } + @Override + public void saveInputs(final Module module) { + module.getInfo().inputs().forEach(item -> saveInput(module, item)); + } + + @Override + public void loadInputs(final Module module) { + module.getInfo().inputs().forEach(item -> loadInput(module, item)); + } + // -- Service methods -- @Override @@ -385,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! @@ -409,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; @@ -420,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 @@ -429,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; @@ -452,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; } @@ -460,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; } } @@ -487,9 +498,8 @@ private ModuleItem getSingleItem(final Module module, for (final ModuleItem item : items) { final String name = item.getName(); - final boolean resolved = module.isInputResolved(name); - if (resolved) continue; // skip resolved inputs if (!item.isAutoFill()) continue; // skip unfillable inputs + if (module.isInputResolved(name)) continue; // skip resolved inputs final Class itemType = item.getType(); for (final Class type : types) { if (type.isAssignableFrom(itemType)) { @@ -523,4 +533,32 @@ private String prefKey(final ModuleItem item) { return persistKey == null || persistKey.isEmpty() ? // item.getName() : persistKey; } + + /** Saves the value of the given module item to persistent storage. */ + private void saveInput(final Module module, final ModuleItem item) { + final T value = item.getValue(module); + save(item, value); + } + + /** Loads the value of the given module item from persistent storage. */ + private void loadInput(final Module module, final ModuleItem item) { + // skip input that has already been resolved + if (module.isInputResolved(item.getName())) return; + + final T prefValue = load(item); + final Class type = item.getType(); + final T defaultValue = item.getValue(module); + final T value = getBestValue(prefValue, defaultValue, type); + item.setValue(module, value); + } + + private T getBestValue(final Object prefValue, + final Object defaultValue, final Class type) + { + if (prefValue != null) return convertService.convert(prefValue, type); + if (defaultValue != null) { + return convertService.convert(defaultValue, type); + } + return Types.nullValue(type); + } } diff --git a/src/main/java/org/scijava/module/DefaultMutableModule.java b/src/main/java/org/scijava/module/DefaultMutableModule.java index c1cc84d16..2d483797a 100644 --- a/src/main/java/org/scijava/module/DefaultMutableModule.java +++ b/src/main/java/org/scijava/module/DefaultMutableModule.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6654c616d..e41f52465 100644 --- a/src/main/java/org/scijava/module/DefaultMutableModuleInfo.java +++ b/src/main/java/org/scijava/module/DefaultMutableModuleInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7a2d3ec23..956d245d6 100644 --- a/src/main/java/org/scijava/module/DefaultMutableModuleItem.java +++ b/src/main/java/org/scijava/module/DefaultMutableModuleItem.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -54,6 +51,7 @@ public class DefaultMutableModuleItem extends AbstractModuleItem private final Type genericType; private ItemIO ioType; private ItemVisibility visibility; + private boolean autoFill; private boolean required; private boolean persisted; private String persistKey; @@ -88,6 +86,7 @@ public DefaultMutableModuleItem(final ModuleInfo info, final String name, genericType = type; ioType = super.getIOType(); visibility = super.getVisibility(); + autoFill = super.isAutoFill(); required = super.isRequired(); persisted = super.isPersisted(); persistKey = super.getPersistKey(); @@ -115,6 +114,7 @@ public DefaultMutableModuleItem(final ModuleInfo info, genericType = item.getGenericType(); ioType = item.getIOType(); visibility = item.getVisibility(); + autoFill = item.isAutoFill(); required = item.isRequired(); persisted = item.isPersisted(); persistKey = item.getPersistKey(); @@ -146,6 +146,11 @@ public void setVisibility(final ItemVisibility visibility) { this.visibility = visibility; } + @Override + public void setAutoFill(final boolean autoFill) { + this.autoFill = autoFill; + } + @Override public void setRequired(final boolean required) { this.required = required; @@ -244,6 +249,11 @@ public ItemVisibility getVisibility() { return visibility; } + @Override + public boolean isAutoFill() { + return autoFill; + } + @Override public boolean isRequired() { return required; diff --git a/src/main/java/org/scijava/module/MethodCallException.java b/src/main/java/org/scijava/module/MethodCallException.java index 970958312..5dd89a0d6 100644 --- a/src/main/java/org/scijava/module/MethodCallException.java +++ b/src/main/java/org/scijava/module/MethodCallException.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 acfa908b4..8dff15695 100644 --- a/src/main/java/org/scijava/module/MethodRef.java +++ b/src/main/java/org/scijava/module/MethodRef.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/Module.java b/src/main/java/org/scijava/module/Module.java index 567602335..a60bd7d3e 100644 --- a/src/main/java/org/scijava/module/Module.java +++ b/src/main/java/org/scijava/module/Module.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 82ae29ef9..cd8cb0cf4 100644 --- a/src/main/java/org/scijava/module/ModuleCanceledException.java +++ b/src/main/java/org/scijava/module/ModuleCanceledException.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2355db95b..c178e6a39 100644 --- a/src/main/java/org/scijava/module/ModuleException.java +++ b/src/main/java/org/scijava/module/ModuleException.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 83da593d6..0b11c9f52 100644 --- a/src/main/java/org/scijava/module/ModuleIndex.java +++ b/src/main/java/org/scijava/module/ModuleIndex.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b442b4300..73e1a59a9 100644 --- a/src/main/java/org/scijava/module/ModuleInfo.java +++ b/src/main/java/org/scijava/module/ModuleInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5b6b43fdb..0007ee040 100644 --- a/src/main/java/org/scijava/module/ModuleItem.java +++ b/src/main/java/org/scijava/module/ModuleItem.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/ModuleRunner.java b/src/main/java/org/scijava/module/ModuleRunner.java index d95e123f0..49879fe71 100644 --- a/src/main/java/org/scijava/module/ModuleRunner.java +++ b/src/main/java/org/scijava/module/ModuleRunner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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; @@ -127,12 +125,10 @@ public Module call() { run(); } catch (final RuntimeException exc) { - if (log != null) log.error("Module threw exception", exc); - throw exc; + throw new RuntimeException("Module threw exception", exc); } catch (final Error err) { - if (log != null) log.error("Module threw error", err); - throw err; + throw new RuntimeException("Module threw error", err); } return module; } @@ -149,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 -- @@ -195,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 9267c0070..8b8ed2f51 100644 --- a/src/main/java/org/scijava/module/ModuleService.java +++ b/src/main/java/org/scijava/module/ModuleService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -311,4 +308,9 @@ Future run(M module, /** Gets the default value of the given {@link ModuleItem}. */ T getDefaultValue(final ModuleItem item); + /** Saves values to persistent storage from the given {@link Module}. */ + void saveInputs(final Module module); + + /** Loads values from persistent storage into the given {@link Module}. */ + void loadInputs(final Module module); } diff --git a/src/main/java/org/scijava/module/MutableModule.java b/src/main/java/org/scijava/module/MutableModule.java index 83d746362..87e839206 100644 --- a/src/main/java/org/scijava/module/MutableModule.java +++ b/src/main/java/org/scijava/module/MutableModule.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 aec08d912..fd3cbbb2d 100644 --- a/src/main/java/org/scijava/module/MutableModuleInfo.java +++ b/src/main/java/org/scijava/module/MutableModuleInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4c2f132fd..a3b4ccc09 100644 --- a/src/main/java/org/scijava/module/MutableModuleItem.java +++ b/src/main/java/org/scijava/module/MutableModuleItem.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -49,6 +46,8 @@ public interface MutableModuleItem extends ModuleItem { void setVisibility(ItemVisibility visibility); + void setAutoFill(boolean autoFill); + void setRequired(boolean required); void setPersisted(boolean persisted); diff --git a/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java b/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java index 80bf49ba9..9016e323a 100644 --- a/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleCanceledEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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..364772b38 --- /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 - 2025 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 4303c40d4..96c3ddca3 100644 --- a/src/main/java/org/scijava/module/event/ModuleEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 58dc9e41c..2942ea56d 100644 --- a/src/main/java/org/scijava/module/event/ModuleExecutedEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleExecutedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 9589e788a..f1fd53f5c 100644 --- a/src/main/java/org/scijava/module/event/ModuleExecutingEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleExecutingEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5c5ed02ef..940a9d8e0 100644 --- a/src/main/java/org/scijava/module/event/ModuleExecutionEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleExecutionEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5ab4b856f..692be5b92 100644 --- a/src/main/java/org/scijava/module/event/ModuleFinishedEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleFinishedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 98a0b2a27..9d42be6ab 100644 --- a/src/main/java/org/scijava/module/event/ModulePostprocessEvent.java +++ b/src/main/java/org/scijava/module/event/ModulePostprocessEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ab8ef93ea..760c2c55f 100644 --- a/src/main/java/org/scijava/module/event/ModulePreprocessEvent.java +++ b/src/main/java/org/scijava/module/event/ModulePreprocessEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4f42cc3d3..b58046091 100644 --- a/src/main/java/org/scijava/module/event/ModuleProcessEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleProcessEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 52647be4e..975c5e8af 100644 --- a/src/main/java/org/scijava/module/event/ModuleStartedEvent.java +++ b/src/main/java/org/scijava/module/event/ModuleStartedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8fa1c18de..aa3b3877c 100644 --- a/src/main/java/org/scijava/module/event/ModulesAddedEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesAddedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 140ee62c0..95b2c1c28 100644 --- a/src/main/java/org/scijava/module/event/ModulesListEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesListEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f37774673..f60959dbc 100644 --- a/src/main/java/org/scijava/module/event/ModulesRemovedEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesRemovedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 067cad90f..a0a14f75d 100644 --- a/src/main/java/org/scijava/module/event/ModulesUpdatedEvent.java +++ b/src/main/java/org/scijava/module/event/ModulesUpdatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7f6231b28..8ac5886d5 100644 --- a/src/main/java/org/scijava/module/process/AbstractPostprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/AbstractPostprocessorPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b1c049a80..4f5f625ca 100644 --- a/src/main/java/org/scijava/module/process/AbstractPreprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/AbstractPreprocessorPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 91abbb0a9..b373722ee 100644 --- a/src/main/java/org/scijava/module/process/AbstractSingleInputPreprocessor.java +++ b/src/main/java/org/scijava/module/process/AbstractSingleInputPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c07a0644c..fff89a404 100644 --- a/src/main/java/org/scijava/module/process/CheckInputsPreprocessor.java +++ b/src/main/java/org/scijava/module/process/CheckInputsPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2cc1e89e5..2760cea81 100644 --- a/src/main/java/org/scijava/module/process/DebugPostprocessor.java +++ b/src/main/java/org/scijava/module/process/DebugPostprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 aeede855e..59db93a4e 100644 --- a/src/main/java/org/scijava/module/process/DebugPreprocessor.java +++ b/src/main/java/org/scijava/module/process/DebugPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cc0d1f7d5..b85d7ce60 100644 --- a/src/main/java/org/scijava/module/process/DefaultValuePreprocessor.java +++ b/src/main/java/org/scijava/module/process/DefaultValuePreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 59c3169cb..c080e8100 100644 --- a/src/main/java/org/scijava/module/process/GatewayPreprocessor.java +++ b/src/main/java/org/scijava/module/process/GatewayPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -64,7 +61,8 @@ public class GatewayPreprocessor extends AbstractPreprocessorPlugin { @Override public void process(final Module module) { for (final ModuleItem input : module.getInfo().inputs()) { - if (!input.isAutoFill()) continue; // cannot auto-fill this input + if (!input.isAutoFill()) continue; // skip unfillable inputs + if (module.isInputResolved(input.getName())) continue; // skip resolved inputs final Class type = input.getType(); if (Gateway.class.isAssignableFrom(type)) { // input is a gateway @@ -87,22 +85,10 @@ private void setGatewayValue(final Context context, try { gateway = type.getConstructor(Context.class).newInstance(context); } - catch (final IllegalArgumentException exc) { - exception = exc; - } - catch (final SecurityException exc) { - exception = exc; - } - catch (final InstantiationException exc) { - exception = exc; - } - catch (final IllegalAccessException exc) { - exception = exc; - } - catch (final InvocationTargetException exc) { - exception = exc; - } - catch (final NoSuchMethodException exc) { + catch (final IllegalArgumentException | SecurityException + | InstantiationException | IllegalAccessException + | InvocationTargetException | NoSuchMethodException exc) + { exception = exc; } if (exception != null) { diff --git a/src/main/java/org/scijava/module/process/InitPreprocessor.java b/src/main/java/org/scijava/module/process/InitPreprocessor.java index b71b961d8..7cbe03d34 100644 --- a/src/main/java/org/scijava/module/process/InitPreprocessor.java +++ b/src/main/java/org/scijava/module/process/InitPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d44d96133..abf184e9f 100644 --- a/src/main/java/org/scijava/module/process/LoadInputsPreprocessor.java +++ b/src/main/java/org/scijava/module/process/LoadInputsPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,13 +29,10 @@ package org.scijava.module.process; -import org.scijava.convert.ConvertService; import org.scijava.module.Module; -import org.scijava.module.ModuleItem; import org.scijava.module.ModuleService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; -import org.scijava.util.Types; import org.scijava.widget.InputHarvester; /** @@ -59,41 +53,8 @@ public class LoadInputsPreprocessor extends AbstractPreprocessorPlugin { @Parameter private ModuleService moduleService; - @Parameter - private ConvertService conversionService; - - // -- ModuleProcessor methods -- - @Override public void process(final Module module) { - final Iterable> inputs = module.getInfo().inputs(); - for (final ModuleItem item : inputs) { - loadValue(module, item); - } - } - - // -- Helper methods -- - - /** Loads the value of the given module item from persistent storage. */ - private void loadValue(final Module module, final ModuleItem item) { - // skip input that has already been resolved - if (module.isInputResolved(item.getName())) return; - - final T prefValue = moduleService.load(item); - final Class type = item.getType(); - final T defaultValue = item.getValue(module); - final T value = getBestValue(prefValue, defaultValue, type); - item.setValue(module, value); + moduleService.loadInputs(module); } - - private T getBestValue(final Object prefValue, - final Object defaultValue, final Class type) - { - if (prefValue != null) return conversionService.convert(prefValue, type); - if (defaultValue != null) { - return conversionService.convert(defaultValue, type); - } - return Types.nullValue(type); - } - } diff --git a/src/main/java/org/scijava/module/process/LoggerPreprocessor.java b/src/main/java/org/scijava/module/process/LoggerPreprocessor.java index 2e62faaf1..2be46df60 100644 --- a/src/main/java/org/scijava/module/process/LoggerPreprocessor.java +++ b/src/main/java/org/scijava/module/process/LoggerPreprocessor.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 @@ -31,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; @@ -46,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 9f3d29ae4..528c6a815 100644 --- a/src/main/java/org/scijava/module/process/ModulePostprocessor.java +++ b/src/main/java/org/scijava/module/process/ModulePostprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e40a7b21c..a1b65e315 100644 --- a/src/main/java/org/scijava/module/process/ModulePreprocessor.java +++ b/src/main/java/org/scijava/module/process/ModulePreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 01daf5446..696e06602 100644 --- a/src/main/java/org/scijava/module/process/ModuleProcessor.java +++ b/src/main/java/org/scijava/module/process/ModuleProcessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e8f346b8b..8c0dc970b 100644 --- a/src/main/java/org/scijava/module/process/PostprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/PostprocessorPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b7081968d..2a13be6e0 100644 --- a/src/main/java/org/scijava/module/process/PreprocessorPlugin.java +++ b/src/main/java/org/scijava/module/process/PreprocessorPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 30f23a49f..0cabffa55 100644 --- a/src/main/java/org/scijava/module/process/SaveInputsPreprocessor.java +++ b/src/main/java/org/scijava/module/process/SaveInputsPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,7 +31,6 @@ import org.scijava.Priority; import org.scijava.module.Module; -import org.scijava.module.ModuleItem; import org.scijava.module.ModuleService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; @@ -59,22 +55,8 @@ public class SaveInputsPreprocessor extends AbstractPreprocessorPlugin { @Parameter private ModuleService moduleService; - // -- ModuleProcessor methods -- - @Override public void process(final Module module) { - final Iterable> inputs = module.getInfo().inputs(); - for (final ModuleItem item : inputs) { - saveValue(module, item); - } + moduleService.saveInputs(module); } - - // -- Helper methods -- - - /** Saves the value of the given module item to persistent storage. */ - private void saveValue(final Module module, final ModuleItem item) { - final T value = item.getValue(module); - moduleService.save(item, value); - } - } diff --git a/src/main/java/org/scijava/module/process/ServicePreprocessor.java b/src/main/java/org/scijava/module/process/ServicePreprocessor.java index 8993cdd46..c195ffa93 100644 --- a/src/main/java/org/scijava/module/process/ServicePreprocessor.java +++ b/src/main/java/org/scijava/module/process/ServicePreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -70,7 +67,8 @@ public class ServicePreprocessor extends AbstractPreprocessorPlugin { @Override public void process(final Module module) { for (final ModuleItem input : module.getInfo().inputs()) { - if (!input.isAutoFill()) continue; // cannot auto-fill this input + if (!input.isAutoFill()) continue; // skip unfillable inputs + if (module.isInputResolved(input.getName())) continue; // skip resolved inputs final Class type = input.getType(); if (Service.class.isAssignableFrom(type)) { // input is a service @@ -79,7 +77,9 @@ public void process(final Module module) { (ModuleItem) input; setServiceValue(getContext(), module, serviceInput); } - if (type.isAssignableFrom(getContext().getClass())) { + if (Context.class.isAssignableFrom(type) && // + type.isAssignableFrom(getContext().getClass())) + { // input is a compatible context final String name = input.getName(); module.setInput(name, getContext()); diff --git a/src/main/java/org/scijava/module/process/ValidityPreprocessor.java b/src/main/java/org/scijava/module/process/ValidityPreprocessor.java index 012d14fe7..78666b9bf 100644 --- a/src/main/java/org/scijava/module/process/ValidityPreprocessor.java +++ b/src/main/java/org/scijava/module/process/ValidityPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e34b1b800..1e6ee836b 100644 --- a/src/main/java/org/scijava/module/run/ModuleCodeRunner.java +++ b/src/main/java/org/scijava/module/run/ModuleCodeRunner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 46f162ab0..ccd8218a1 100644 --- a/src/main/java/org/scijava/object/DefaultObjectService.java +++ b/src/main/java/org/scijava/object/DefaultObjectService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,14 +29,10 @@ package org.scijava.object; -import java.util.List; - import org.scijava.event.EventHandler; import org.scijava.event.EventService; import org.scijava.object.event.ObjectCreatedEvent; import org.scijava.object.event.ObjectDeletedEvent; -import org.scijava.object.event.ObjectsAddedEvent; -import org.scijava.object.event.ObjectsRemovedEvent; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; import org.scijava.service.AbstractService; @@ -68,7 +61,7 @@ public final class DefaultObjectService extends AbstractService implements private EventService eventService; /** Index of registered objects. */ - private ObjectIndex objectIndex; + private NamedObjectIndex objectIndex; // -- ObjectService methods -- @@ -78,35 +71,15 @@ public EventService eventService() { } @Override - public ObjectIndex getIndex() { + public NamedObjectIndex getIndex() { return objectIndex; } - @Override - public List getObjects(final Class type) { - final List list = objectIndex.get(type); - @SuppressWarnings("unchecked") - final List result = (List) list; - return result; - } - - @Override - public void addObject(final Object obj) { - objectIndex.add(obj); - eventService.publish(new ObjectsAddedEvent(obj)); - } - - @Override - public void removeObject(final Object obj) { - objectIndex.remove(obj); - eventService.publish(new ObjectsRemovedEvent(obj)); - } - // -- Service methods -- @Override public void initialize() { - objectIndex = new ObjectIndex<>(Object.class); + objectIndex = new NamedObjectIndex<>(Object.class); } // -- Event handlers -- @@ -120,5 +93,4 @@ protected void onEvent(final ObjectCreatedEvent event) { protected void onEvent(final ObjectDeletedEvent event) { removeObject(event.getObject()); } - } diff --git a/src/main/java/org/scijava/object/LazyObjects.java b/src/main/java/org/scijava/object/LazyObjects.java index e1d0d660e..7a2ac555a 100644 --- a/src/main/java/org/scijava/object/LazyObjects.java +++ b/src/main/java/org/scijava/object/LazyObjects.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 new file mode 100644 index 000000000..a05f326f1 --- /dev/null +++ b/src/main/java/org/scijava/object/NamedObjectIndex.java @@ -0,0 +1,62 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.object; + +import java.util.WeakHashMap; + +/** + * An {@link ObjectIndex} where each object can have an associated name. + * + * @author Jan Eglinger + */ +public class NamedObjectIndex extends ObjectIndex { + + private WeakHashMap nameMap; + + public NamedObjectIndex(final Class baseClass) { + super(baseClass); + nameMap = new WeakHashMap<>(); + } + + public boolean add(E object, String name) { + if (name != null) + nameMap.put(object, name); + return add(object); + } + + public boolean add(E object, Class type, String name, boolean batch) { + if (name != null) + nameMap.put(object, name); + return add(object, type, batch); + } + + public String getName(E object) { + return nameMap.get(object); + } +} diff --git a/src/main/java/org/scijava/object/ObjectIndex.java b/src/main/java/org/scijava/object/ObjectIndex.java index 04c174cb5..c8c9df2c5 100644 --- a/src/main/java/org/scijava/object/ObjectIndex.java +++ b/src/main/java/org/scijava/object/ObjectIndex.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e24922b21..478be8af1 100644 --- a/src/main/java/org/scijava/object/ObjectService.java +++ b/src/main/java/org/scijava/object/ObjectService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,7 +31,10 @@ import java.util.List; +import org.scijava.Named; import org.scijava.event.EventService; +import org.scijava.object.event.ObjectsAddedEvent; +import org.scijava.object.event.ObjectsRemovedEvent; import org.scijava.service.SciJavaService; /** @@ -49,16 +49,54 @@ default EventService eventService() { } /** Gets the index of available objects. */ - ObjectIndex getIndex(); + NamedObjectIndex getIndex(); /** Gets a list of all registered objects compatible with the given type. */ - List getObjects(Class type); + default List getObjects(final Class type) { + final List list = getIndex().get(type); + @SuppressWarnings("unchecked") + final List result = (List) list; + return result; + } + + /** + * Gets the name belonging to a given object. + *

+ * If no explicit name was provided at registration time, the name will be + * derived from {@link Named#getName()} if the object implements + * {@link Named}, or from the {@link Object#toString()} otherwise. It is + * guaranteed that this method will not return {@code null}. + *

+ **/ + default String getName(final Object obj) { + if (obj == null) throw new NullPointerException(); + final String name = getIndex().getName(obj); + if (name != null) return name; + if (obj instanceof Named) { + final String n = ((Named) obj).getName(); + if (n != null) return n; + } + final String s = obj.toString(); + if (s != null) return s; + return obj.getClass().getName() + "@" + Integer.toHexString(obj.hashCode()); + } /** Registers an object with the object service. */ - void addObject(Object obj); + default void addObject(Object obj) { + addObject(obj, null); + } + + /** Registers a named object with the object service. */ + default void addObject(final Object obj, final String name) { + getIndex().add(obj, name); + eventService().publish(new ObjectsAddedEvent(obj)); + } /** Deregisters an object with the object service. */ - void removeObject(Object obj); + default void removeObject(final Object obj) { + getIndex().remove(obj); + eventService().publish(new ObjectsRemovedEvent(obj)); + } // -- Deprecated methods -- diff --git a/src/main/java/org/scijava/object/SortedObjectIndex.java b/src/main/java/org/scijava/object/SortedObjectIndex.java index 690ff025d..0ffec7b19 100644 --- a/src/main/java/org/scijava/object/SortedObjectIndex.java +++ b/src/main/java/org/scijava/object/SortedObjectIndex.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ee97f715a..d13533817 100644 --- a/src/main/java/org/scijava/object/event/ListEvent.java +++ b/src/main/java/org/scijava/object/event/ListEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6d7ea3c52..53ad97b26 100644 --- a/src/main/java/org/scijava/object/event/ObjectCreatedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectCreatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1cda244d8..1825bbc87 100644 --- a/src/main/java/org/scijava/object/event/ObjectDeletedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectDeletedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5b4d8e68a..e2b5abe73 100644 --- a/src/main/java/org/scijava/object/event/ObjectEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 44b289518..e87836338 100644 --- a/src/main/java/org/scijava/object/event/ObjectModifiedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectModifiedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a924dcf5c..7487ee5ed 100644 --- a/src/main/java/org/scijava/object/event/ObjectsAddedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectsAddedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 699cc48b0..de8aaf9e2 100644 --- a/src/main/java/org/scijava/object/event/ObjectsListEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectsListEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 20b505c6a..2bf0f49ff 100644 --- a/src/main/java/org/scijava/object/event/ObjectsRemovedEvent.java +++ b/src/main/java/org/scijava/object/event/ObjectsRemovedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 706eb0579..a7239d833 100644 --- a/src/main/java/org/scijava/options/DefaultOptionsService.java +++ b/src/main/java/org/scijava/options/DefaultOptionsService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6d9c75825..815c640e9 100644 --- a/src/main/java/org/scijava/options/OptionsPlugin.java +++ b/src/main/java/org/scijava/options/OptionsPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +32,6 @@ import org.scijava.command.DynamicCommand; import org.scijava.event.EventService; import org.scijava.module.ModuleItem; -import org.scijava.module.ModuleService; import org.scijava.options.event.OptionsEvent; import org.scijava.plugin.Parameter; import org.scijava.plugin.SingletonPlugin; @@ -84,9 +80,6 @@ public abstract class OptionsPlugin extends DynamicCommand implements @Parameter private PrefService prefService; - @Parameter - private ModuleService moduleService; - // -- OptionsPlugin methods -- /** Loads option values from persistent storage. */ diff --git a/src/main/java/org/scijava/options/OptionsService.java b/src/main/java/org/scijava/options/OptionsService.java index 199478d05..fcb68ed08 100644 --- a/src/main/java/org/scijava/options/OptionsService.java +++ b/src/main/java/org/scijava/options/OptionsService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6e2712b02..20cc74f48 100644 --- a/src/main/java/org/scijava/options/event/OptionsEvent.java +++ b/src/main/java/org/scijava/options/event/OptionsEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3e5f5384e..b686d558b 100644 --- a/src/main/java/org/scijava/parse/DefaultParseService.java +++ b/src/main/java/org/scijava/parse/DefaultParseService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,7 +34,8 @@ import java.util.List; import java.util.Map; -import org.scijava.parse.eval.DefaultEvaluator; +import org.scijava.parsington.Variable; +import org.scijava.parsington.eval.DefaultTreeEvaluator; import org.scijava.plugin.Plugin; import org.scijava.service.AbstractService; import org.scijava.service.Service; @@ -62,9 +60,8 @@ public Items parse(final String arg, final boolean strict) { // -- Helper classes -- /** - * {@link Items} implementation backed by the - * SciJava - * Expression Parser. + * {@link Items} implementation backed by + * Parsington. */ private static class ItemsList extends ObjectArray implements Items { @@ -100,7 +97,7 @@ public boolean isList() { } private void parseItems(final String arg, final boolean strict) { - final DefaultEvaluator e = new DefaultEvaluator(); + final DefaultTreeEvaluator e = new DefaultTreeEvaluator(); e.setStrict(strict); final Object result = e.evaluate("(" + arg + ")"); if (result == null) { diff --git a/src/main/java/org/scijava/parse/Item.java b/src/main/java/org/scijava/parse/Item.java index c08d40764..4cba11748 100644 --- a/src/main/java/org/scijava/parse/Item.java +++ b/src/main/java/org/scijava/parse/Item.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a1a47320c..49dbaf9ad 100644 --- a/src/main/java/org/scijava/parse/Items.java +++ b/src/main/java/org/scijava/parse/Items.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 870893e6f..ba20fb813 100644 --- a/src/main/java/org/scijava/parse/ParseService.java +++ b/src/main/java/org/scijava/parse/ParseService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e0437cd04..f20f49b14 100644 --- a/src/main/java/org/scijava/platform/AbstractPlatform.java +++ b/src/main/java/org/scijava/platform/AbstractPlatform.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 12dad7a43..16b191878 100644 --- a/src/main/java/org/scijava/platform/AppEventService.java +++ b/src/main/java/org/scijava/platform/AppEventService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 450710084..bd0c34424 100644 --- a/src/main/java/org/scijava/platform/DefaultAppEventService.java +++ b/src/main/java/org/scijava/platform/DefaultAppEventService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 06124c883..96e18fded 100644 --- a/src/main/java/org/scijava/platform/DefaultPlatform.java +++ b/src/main/java/org/scijava/platform/DefaultPlatform.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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; /** @@ -47,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 -- /** @@ -69,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 b0ded7629..e5effaaf1 100644 --- a/src/main/java/org/scijava/platform/DefaultPlatformService.java +++ b/src/main/java/org/scijava/platform/DefaultPlatformService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 840e03c46..96e0e6743 100644 --- a/src/main/java/org/scijava/platform/Platform.java +++ b/src/main/java/org/scijava/platform/Platform.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 53f56d85d..68e07fe9f 100644 --- a/src/main/java/org/scijava/platform/PlatformService.java +++ b/src/main/java/org/scijava/platform/PlatformService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7bc964bdb..251d253a7 100644 --- a/src/main/java/org/scijava/platform/event/AppAboutEvent.java +++ b/src/main/java/org/scijava/platform/event/AppAboutEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a4364de88..8d1278a2f 100644 --- a/src/main/java/org/scijava/platform/event/AppFocusEvent.java +++ b/src/main/java/org/scijava/platform/event/AppFocusEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 72b90558b..23b119891 100644 --- a/src/main/java/org/scijava/platform/event/AppMenusCreatedEvent.java +++ b/src/main/java/org/scijava/platform/event/AppMenusCreatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 bc6e98bc4..0a5d85fa7 100644 --- a/src/main/java/org/scijava/platform/event/AppOpenFilesEvent.java +++ b/src/main/java/org/scijava/platform/event/AppOpenFilesEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 494372e96..c5221df29 100644 --- a/src/main/java/org/scijava/platform/event/AppPreferencesEvent.java +++ b/src/main/java/org/scijava/platform/event/AppPreferencesEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b89404a7d..0c764a718 100644 --- a/src/main/java/org/scijava/platform/event/AppPrintEvent.java +++ b/src/main/java/org/scijava/platform/event/AppPrintEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6f8f3ff08..c3198e627 100644 --- a/src/main/java/org/scijava/platform/event/AppQuitEvent.java +++ b/src/main/java/org/scijava/platform/event/AppQuitEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 db1fe918b..47a252476 100644 --- a/src/main/java/org/scijava/platform/event/AppReOpenEvent.java +++ b/src/main/java/org/scijava/platform/event/AppReOpenEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4396d87d7..c78337b1a 100644 --- a/src/main/java/org/scijava/platform/event/AppScreenSleepEvent.java +++ b/src/main/java/org/scijava/platform/event/AppScreenSleepEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a8545571b..eb3b09762 100644 --- a/src/main/java/org/scijava/platform/event/AppSleepEvent.java +++ b/src/main/java/org/scijava/platform/event/AppSleepEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 81c23b321..8e29b17a3 100644 --- a/src/main/java/org/scijava/platform/event/AppSystemSleepEvent.java +++ b/src/main/java/org/scijava/platform/event/AppSystemSleepEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8adcbb90d..b5d608118 100644 --- a/src/main/java/org/scijava/platform/event/AppUserSessionEvent.java +++ b/src/main/java/org/scijava/platform/event/AppUserSessionEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 88d6d71fb..8a029561d 100644 --- a/src/main/java/org/scijava/platform/event/AppVisibleEvent.java +++ b/src/main/java/org/scijava/platform/event/AppVisibleEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0114a3231..4856c0748 100644 --- a/src/main/java/org/scijava/platform/event/ApplicationEvent.java +++ b/src/main/java/org/scijava/platform/event/ApplicationEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 358baa2f5..995bde741 100644 --- a/src/main/java/org/scijava/plugin/AbstractHandlerPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractHandlerPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a0bd36719..af501d619 100644 --- a/src/main/java/org/scijava/plugin/AbstractHandlerService.java +++ b/src/main/java/org/scijava/plugin/AbstractHandlerService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 03145e616..e84ad8c07 100644 --- a/src/main/java/org/scijava/plugin/AbstractPTService.java +++ b/src/main/java/org/scijava/plugin/AbstractPTService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 30b46b66d..73c37cb3f 100644 --- a/src/main/java/org/scijava/plugin/AbstractRichPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractRichPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b5791f769..497528dc8 100644 --- a/src/main/java/org/scijava/plugin/AbstractSingletonService.java +++ b/src/main/java/org/scijava/plugin/AbstractSingletonService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,13 +29,17 @@ package org.scijava.plugin; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.scijava.event.EventHandler; import org.scijava.log.LogService; import org.scijava.object.ObjectService; +import org.scijava.plugin.event.PluginsAddedEvent; +import org.scijava.plugin.event.PluginsRemovedEvent; /** * Abstract base class for {@link SingletonService}s. @@ -56,9 +57,6 @@ public abstract class AbstractSingletonService @Parameter private ObjectService objectService; - // TODO: Listen for PluginsAddedEvent and PluginsRemovedEvent - // and update the list of singletons accordingly. - /** List of singleton plugin instances. */ private List instances; @@ -74,7 +72,7 @@ public ObjectService objectService() { @Override public List getInstances() { if (instances == null) initInstances(); - return instances; + return Collections.unmodifiableList(instances); } @SuppressWarnings("unchecked") @@ -84,20 +82,63 @@ public

P getInstance(final Class

pluginClass) { return (P) instanceMap.get(pluginClass); } +//-- Event handlers -- + + @EventHandler + protected void onEvent(final PluginsRemovedEvent event) { + if (instanceMap == null) return; + for (final PluginInfo info : event.getItems()) { + final PT obj = instanceMap.remove(info.getPluginClass()); + if (obj != null) { // we actually removed a plugin + instances.remove(obj); + objectService.removeObject(obj); + } + } + } + + @EventHandler + protected void onEvent(final PluginsAddedEvent event) { + if (instanceMap == null) return; + // collect singleton plugins + final List> singletons = new ArrayList<>(); + for (final PluginInfo pluginInfo : event.getItems()) { + if (getPluginType().isAssignableFrom(pluginInfo.getPluginType())) { + @SuppressWarnings("unchecked") + final PT plugin = pluginService().createInstance( + (PluginInfo) pluginInfo); + @SuppressWarnings("unchecked") + final Class pluginClass = (Class) plugin + .getClass(); + instanceMap.put(pluginClass, plugin); + instances.add(plugin); + } + } + + for (final PluginInfo pluginInfo : singletons) { + final PT plugin = pluginService().createInstance(pluginInfo); + @SuppressWarnings("unchecked") + final Class pluginClass = (Class) plugin + .getClass(); + instanceMap.put(pluginClass, plugin); + instances.add(plugin); + } + + } + // -- Helper methods -- private synchronized void initInstances() { if (instances != null) return; - final List list = Collections.unmodifiableList(filterInstances( - pluginService().createInstancesOfType(getPluginType()))); + @SuppressWarnings("unchecked") + final List list = (List) filterInstances(pluginService() + .createInstancesOfType(getPluginType())); - final HashMap, PT> map = - new HashMap<>(); + final Map, PT> map = new HashMap<>(); for (final PT plugin : list) { @SuppressWarnings("unchecked") - final Class ptClass = + final Class ptClass = // (Class) plugin.getClass(); map.put(ptClass, plugin); } diff --git a/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java b/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java index 52b82ef2c..46dc75ead 100644 --- a/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractTypedPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7c71dfd51..9929517f2 100644 --- a/src/main/java/org/scijava/plugin/AbstractTypedService.java +++ b/src/main/java/org/scijava/plugin/AbstractTypedService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ca7cfafad..9f0281c74 100644 --- a/src/main/java/org/scijava/plugin/AbstractWrapperPlugin.java +++ b/src/main/java/org/scijava/plugin/AbstractWrapperPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4795a5810..b60bca1ae 100644 --- a/src/main/java/org/scijava/plugin/AbstractWrapperService.java +++ b/src/main/java/org/scijava/plugin/AbstractWrapperService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 08aac65da..717550439 100644 --- a/src/main/java/org/scijava/plugin/Attr.java +++ b/src/main/java/org/scijava/plugin/Attr.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3081cd34e..e2eb4949c 100644 --- a/src/main/java/org/scijava/plugin/DefaultPluginFinder.java +++ b/src/main/java/org/scijava/plugin/DefaultPluginFinder.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,6 +35,7 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import org.scijava.Context; import org.scijava.annotations.Index; import org.scijava.annotations.IndexItem; @@ -55,7 +53,7 @@ public class DefaultPluginFinder implements PluginFinder { /** Class loader to use when querying the annotation indexes. */ private final ClassLoader customClassLoader; - private final PluginBlacklist blacklist; + private final PluginBlocklist blocklist; // -- Constructors -- @@ -65,7 +63,7 @@ public DefaultPluginFinder() { public DefaultPluginFinder(final ClassLoader classLoader) { customClassLoader = classLoader; - blacklist = new SysPropBlacklist(); + blocklist = new SysPropBlocklist(); } // -- PluginFinder methods -- @@ -84,7 +82,7 @@ public HashMap findPlugins( // create a PluginInfo object for each item in the index for (final IndexItem item : annotationIndex) { - if (blacklist.contains(item.className())) continue; + if (blocklist.contains(item.className())) continue; try { final PluginInfo info = createInfo(item, classLoader); plugins.add(info); @@ -113,29 +111,29 @@ private PluginInfo createInfo( } private ClassLoader getClassLoader() { - if (customClassLoader != null) return customClassLoader; - return Thread.currentThread().getContextClassLoader(); + return customClassLoader != null ? // + customClassLoader : Context.getClassLoader(); } // -- Helper classes -- - private interface PluginBlacklist { + private interface PluginBlocklist { boolean contains(String className); } /** - * A blacklist defined by the {@code scijava.plugin.blacklist} system + * A blocklist defined by the {@code scijava.plugin.blocklist} system * property, formatted as a colon-separated list of regexes. *

* If a plugin class matches any of the regexes, it is excluded from the * plugin index. *

*/ - private class SysPropBlacklist implements PluginBlacklist { + private class SysPropBlocklist implements PluginBlocklist { private final List patterns; - public SysPropBlacklist() { - final String sysProp = System.getProperty("scijava.plugin.blacklist"); + public SysPropBlocklist() { + final String sysProp = System.getProperty("scijava.plugin.blocklist"); final String[] regexes = // sysProp == null ? new String[0] : sysProp.split(":"); patterns = new ArrayList<>(regexes.length); @@ -149,7 +147,7 @@ public SysPropBlacklist() { } } - // -- PluginBlacklist methods -- + // -- PluginBlocklist methods -- @Override public boolean contains(final String className) { diff --git a/src/main/java/org/scijava/plugin/DefaultPluginService.java b/src/main/java/org/scijava/plugin/DefaultPluginService.java index dc61d9ab7..8193d8d5e 100644 --- a/src/main/java/org/scijava/plugin/DefaultPluginService.java +++ b/src/main/java/org/scijava/plugin/DefaultPluginService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -239,7 +236,10 @@ public List createInstances( return p; } catch (final Throwable t) { - log.error("Cannot create plugin: " + info, t); + final String errorMessage = // + "Cannot create plugin: " + info.getClassName(); + if (log.isDebug()) log.debug(errorMessage, t); + else log.error(errorMessage); } return null; } diff --git a/src/main/java/org/scijava/plugin/HandlerPlugin.java b/src/main/java/org/scijava/plugin/HandlerPlugin.java index 9dfe36a7a..33f179bfb 100644 --- a/src/main/java/org/scijava/plugin/HandlerPlugin.java +++ b/src/main/java/org/scijava/plugin/HandlerPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 21eaf4e80..65a3374b8 100644 --- a/src/main/java/org/scijava/plugin/HandlerService.java +++ b/src/main/java/org/scijava/plugin/HandlerService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -57,7 +54,12 @@ public interface HandlerService> extends */ default PT getHandler(final DT data) { for (final PT handler : getInstances()) { - if (handler.supports(data)) return handler; + try { + if (handler.supports(data)) return handler; + } + catch (final Throwable t) { + log().error("Malfunctioning plugin: " + handler.getClass().getName(), t); + } } return null; } diff --git a/src/main/java/org/scijava/plugin/HasPluginInfo.java b/src/main/java/org/scijava/plugin/HasPluginInfo.java index 4e359bd91..ee65fb550 100644 --- a/src/main/java/org/scijava/plugin/HasPluginInfo.java +++ b/src/main/java/org/scijava/plugin/HasPluginInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 9b031c836..a0b504779 100644 --- a/src/main/java/org/scijava/plugin/Menu.java +++ b/src/main/java/org/scijava/plugin/Menu.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 990535a43..8157261cf 100644 --- a/src/main/java/org/scijava/plugin/PTService.java +++ b/src/main/java/org/scijava/plugin/PTService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3d0f14077..c21d89fbc 100644 --- a/src/main/java/org/scijava/plugin/Parameter.java +++ b/src/main/java/org/scijava/plugin/Parameter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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 3a084f7ef..5e64f9411 100644 --- a/src/main/java/org/scijava/plugin/Plugin.java +++ b/src/main/java/org/scijava/plugin/Plugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 59310b635..3539c7861 100644 --- a/src/main/java/org/scijava/plugin/PluginFinder.java +++ b/src/main/java/org/scijava/plugin/PluginFinder.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 78866bbe8..73153bcb9 100644 --- a/src/main/java/org/scijava/plugin/PluginIndex.java +++ b/src/main/java/org/scijava/plugin/PluginIndex.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -91,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 420323dbf..8e4a4ce85 100644 --- a/src/main/java/org/scijava/plugin/PluginInfo.java +++ b/src/main/java/org/scijava/plugin/PluginInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +30,8 @@ package org.scijava.plugin; import java.net.URL; +import java.util.Collection; +import java.util.Optional; import org.scijava.AbstractUIDetails; import org.scijava.Identifiable; @@ -45,7 +44,6 @@ import org.scijava.UIDetails; import org.scijava.Versioned; import org.scijava.input.Accelerator; -import org.scijava.util.ClassUtils; import org.scijava.util.StringMaker; import org.scijava.util.Types; import org.scijava.util.VersionUtils; @@ -320,12 +318,7 @@ public PT createInstance() throws InstantiableException { @Override public String getIdentifier() { - try { - return "plugin:" + loadClass(); - } - catch (final InstantiableException exc) { - return null; - } + return "plugin:" + getClassName(); } // -- Locatable methods -- @@ -352,6 +345,143 @@ public String getVersion() { } } + // -- Utility methods -- + + /** + * Finds a {@link PluginInfo} of the given plugin class in the specified + * {@link PluginIndex}. Note that to avoid loading plugin classes, class + * identity is determined by class name equality only. + * + * @param pluginClass The concrete class of the plugin whose + * {@link PluginInfo} is desired. + * @param pluginIndex The {@link PluginIndex} to search for a matching + * {@link PluginInfo}. + * @return The matching {@link PluginInfo}, or null if none found. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static

PluginInfo get( + final Class

pluginClass, final PluginIndex pluginIndex) + { + return get(pluginClass, (Collection) pluginIndex.getAll()); + } + + /** + * Finds a {@link PluginInfo} of the given plugin class and plugin type in the + * specified {@link PluginIndex}. Note that to avoid loading plugin + * classes, class identity is determined by class name equality only. + * + * @param pluginClass The concrete class of the plugin whose + * {@link PluginInfo} is desired. + * @param pluginType The type of the plugin; see {@link #getPluginType()}. + * @param pluginIndex The {@link PluginIndex} to search for a matching + * {@link PluginInfo}. + * @return The matching {@link PluginInfo}, or null if none found. + */ + public static

PluginInfo get( + final Class

pluginClass, final Class pluginType, + final PluginIndex pluginIndex) + { + return get(pluginClass, pluginIndex.getPlugins(pluginType)); + } + + /** + * Finds a {@link PluginInfo} of the given plugin class in the specified list + * of plugins. Note that to avoid loading plugin classes, class identity + * is determined by class name equality only. + * + * @param pluginClass The concrete class of the plugin whose + * {@link PluginInfo} is desired. + * @param plugins The list of plugins to search for a match. + * @return The matching {@link PluginInfo}, or null if none found. + */ + public static

PluginInfo get( + final Class

pluginClass, + final Collection> plugins) + { + final String className = pluginClass.getName(); + final Optional> result = plugins.stream() // + .filter(info -> info.getClassName().equals(className)) // + .findFirst(); + return result.isPresent() ? result.get() : null; + } + + /** + * Creates a {@link PluginInfo} for the given plugin class. The class must be + * a concrete class annotated with the @{@link Plugin} annotation, from which + * the plugin type will be inferred. + * + * @param pluginClass The concrete class of the plugin for which a new + * {@link PluginInfo} is desired. + * @return A newly created {@link PluginInfo} for the given plugin class. + * @throws IllegalArgumentException if the given class is not annotated + * with @{@link Plugin}, or its annotated {@link Plugin#type() + * type()} is not a supertype of the plugin class. + */ + public static PluginInfo create( + final Class pluginClass) + { + @SuppressWarnings({ "rawtypes", "unchecked" }) + final PluginInfo info = new PluginInfo(pluginClass, // + pluginType(pluginClass)); + return info; + } + + /** + * Creates a {@link PluginInfo} for the given plugin class of the specified + * plugin type. + * + * @param pluginClass The concrete class of the plugin for which a new + * {@link PluginInfo} is desired. + * @param pluginType The type of the plugin; see {@link #getPluginType()}. + * @return A newly created {@link PluginInfo} for the given plugin class. + */ + public static

PluginInfo create( + final Class

pluginClass, final Class pluginType) + { + return new PluginInfo<>(pluginClass, pluginType); + } + + /** + * Obtains a {@link PluginInfo} for the given plugin class. If one already + * exists in the specified {@link PluginIndex}, it is retrieved (see + * {@link #get(Class, PluginIndex)}); otherwise, a new one is created (see + * {@link #create(Class)}) but not added to the index. + * + * @param pluginClass The concrete class of the plugin whose + * {@link PluginInfo} is desired. + * @param pluginIndex The {@link PluginIndex} to search for a matching + * {@link PluginInfo}. + * @throws IllegalArgumentException when creating a new {@link PluginInfo} if + * the associated plugin type cannot be inferred; see + * {@link #create(Class)}. + */ + public static

PluginInfo getOrCreate( + final Class

pluginClass, final PluginIndex pluginIndex) + { + final PluginInfo existing = get(pluginClass, pluginIndex); + return existing == null ? create(pluginClass) : existing; + } + + /** + * Obtains a {@link PluginInfo} for the given plugin class. If one already + * exists in the specified {@link PluginIndex}, it is retrieved (see + * {@link #get(Class, PluginIndex)}); otherwise, a new one is created (see + * {@link #create(Class)}) but not added to the index. + * + * @param pluginClass The concrete class of the plugin whose + * {@link PluginInfo} is desired. + * @param pluginType The type of the plugin; see {@link #getPluginType()}. + * @param pluginIndex The {@link PluginIndex} to search for a matching + * {@link PluginInfo}. + */ + public static

PluginInfo + getOrCreate(final Class

pluginClass, final Class pluginType, + final PluginIndex pluginIndex) + { + final PluginInfo existing = get(pluginClass, pluginType, pluginIndex); + return existing == null ? create(pluginClass, pluginType) : existing; + } + // -- Helper methods -- /** Populates the entry to match the associated @{@link Plugin} annotation. */ @@ -413,4 +543,23 @@ private MenuPath parseMenuPath(final Menu[] menu) { return menuPath; } + /** Extracts the plugin type from a class's @{@link Plugin} annotation. */ + private static

Class pluginType( + final Class

pluginClass) + { + final Plugin annotation = pluginClass.getAnnotation(Plugin.class); + if (annotation == null) { + throw new IllegalArgumentException( + "Cannot infer plugin type from class '" + pluginClass.getName() + + "' with no @Plugin annotation."); + } + final Class type = annotation.type(); + if (!type.isAssignableFrom(pluginClass)) { + throw new IllegalArgumentException("Invalid plugin type '" + // + type.getName() + "' for class '" + pluginClass.getName() + "'"); + } + @SuppressWarnings("unchecked") + final Class pluginType = (Class) type; + return pluginType; + } } diff --git a/src/main/java/org/scijava/plugin/PluginService.java b/src/main/java/org/scijava/plugin/PluginService.java index 36adb07a7..dc579969a 100644 --- a/src/main/java/org/scijava/plugin/PluginService.java +++ b/src/main/java/org/scijava/plugin/PluginService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 33ab3e9f4..aa5c1d546 100644 --- a/src/main/java/org/scijava/plugin/RichPlugin.java +++ b/src/main/java/org/scijava/plugin/RichPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cfcda7d6a..4bef823d5 100644 --- a/src/main/java/org/scijava/plugin/SciJavaPlugin.java +++ b/src/main/java/org/scijava/plugin/SciJavaPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8be6a7b9a..87e3afba9 100644 --- a/src/main/java/org/scijava/plugin/SingletonPlugin.java +++ b/src/main/java/org/scijava/plugin/SingletonPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8784d34b2..9171d8f8d 100644 --- a/src/main/java/org/scijava/plugin/SingletonService.java +++ b/src/main/java/org/scijava/plugin/SingletonService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +32,6 @@ import java.util.ArrayList; import java.util.List; -import org.scijava.object.LazyObjects; import org.scijava.object.ObjectService; /** @@ -95,13 +91,7 @@ default

P create(final Class

pluginClass) { @Override default void initialize() { // add singleton instances to the object index... IN THE FUTURE! - objectService().getIndex().addLater(new LazyObjects() { - - @Override - public ArrayList get() { - return new ArrayList<>(getInstances()); - } - }); + objectService().getIndex().addLater(() -> new ArrayList<>(getInstances())); } } diff --git a/src/main/java/org/scijava/plugin/SortablePlugin.java b/src/main/java/org/scijava/plugin/SortablePlugin.java index e031af5bb..5b29d8a12 100644 --- a/src/main/java/org/scijava/plugin/SortablePlugin.java +++ b/src/main/java/org/scijava/plugin/SortablePlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2e451c992..c6d04b019 100644 --- a/src/main/java/org/scijava/plugin/TypedPlugin.java +++ b/src/main/java/org/scijava/plugin/TypedPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 11c5a1b0b..a49b329bb 100644 --- a/src/main/java/org/scijava/plugin/TypedService.java +++ b/src/main/java/org/scijava/plugin/TypedService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -68,8 +65,13 @@ public interface TypedService> extends */ default PT find(final DT data) { for (final PluginInfo plugin : getPlugins()) { - final PT instance = pluginService().createInstance(plugin); - if (instance != null && instance.supports(data)) return instance; + try { + final PT instance = pluginService().createInstance(plugin); + if (instance != null && instance.supports(data)) return instance; + } + catch (final Throwable t) { + log().error("Malfunctioning plugin: " + plugin.getClassName(), t); + } } return null; } diff --git a/src/main/java/org/scijava/plugin/WrapperPlugin.java b/src/main/java/org/scijava/plugin/WrapperPlugin.java index 06ad76eaa..62efbea8c 100644 --- a/src/main/java/org/scijava/plugin/WrapperPlugin.java +++ b/src/main/java/org/scijava/plugin/WrapperPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6e4483e02..593a4f797 100644 --- a/src/main/java/org/scijava/plugin/WrapperService.java +++ b/src/main/java/org/scijava/plugin/WrapperService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ed19ddcf5..0caad3bfb 100644 --- a/src/main/java/org/scijava/plugin/event/PluginsAddedEvent.java +++ b/src/main/java/org/scijava/plugin/event/PluginsAddedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3fd7a5d32..edaf3dbb1 100644 --- a/src/main/java/org/scijava/plugin/event/PluginsListEvent.java +++ b/src/main/java/org/scijava/plugin/event/PluginsListEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d4636239a..1709f484c 100644 --- a/src/main/java/org/scijava/plugin/event/PluginsRemovedEvent.java +++ b/src/main/java/org/scijava/plugin/event/PluginsRemovedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 350fe27b1..1bf55eb1a 100644 --- a/src/main/java/org/scijava/prefs/AbstractPrefService.java +++ b/src/main/java/org/scijava/prefs/AbstractPrefService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 92ae62f8f..78efeae4a 100644 --- a/src/main/java/org/scijava/prefs/DefaultPrefService.java +++ b/src/main/java/org/scijava/prefs/DefaultPrefService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b039d970b..d2e285d0d 100644 --- a/src/main/java/org/scijava/prefs/PrefService.java +++ b/src/main/java/org/scijava/prefs/PrefService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8bacf6a95..e60bc4f64 100644 --- a/src/main/java/org/scijava/run/AbstractCodeRunner.java +++ b/src/main/java/org/scijava/run/AbstractCodeRunner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 56fe2954b..9bef19655 100644 --- a/src/main/java/org/scijava/run/CodeRunner.java +++ b/src/main/java/org/scijava/run/CodeRunner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b8aee1b27..ef8bee6e3 100644 --- a/src/main/java/org/scijava/run/DefaultRunService.java +++ b/src/main/java/org/scijava/run/DefaultRunService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ab6ca65be..0c030b383 100644 --- a/src/main/java/org/scijava/run/RunService.java +++ b/src/main/java/org/scijava/run/RunService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0ee722664..ce84a31cf 100644 --- a/src/main/java/org/scijava/run/console/RunArgument.java +++ b/src/main/java/org/scijava/run/console/RunArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 981653d9c..b5b784448 100644 --- a/src/main/java/org/scijava/script/AbstractAutoCompleter.java +++ b/src/main/java/org/scijava/script/AbstractAutoCompleter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7b8409a03..30ccac002 100644 --- a/src/main/java/org/scijava/script/AbstractScriptContext.java +++ b/src/main/java/org/scijava/script/AbstractScriptContext.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cdbb2252d..6875cd203 100644 --- a/src/main/java/org/scijava/script/AbstractScriptEngine.java +++ b/src/main/java/org/scijava/script/AbstractScriptEngine.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 819d79c8d..131ebe7bb 100644 --- a/src/main/java/org/scijava/script/AbstractScriptHeader.java +++ b/src/main/java/org/scijava/script/AbstractScriptHeader.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cd29ceb33..1aa04fbba 100644 --- a/src/main/java/org/scijava/script/AbstractScriptLanguage.java +++ b/src/main/java/org/scijava/script/AbstractScriptLanguage.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e69de8bf3..3c7acd8ef 100644 --- a/src/main/java/org/scijava/script/AdaptedScriptEngine.java +++ b/src/main/java/org/scijava/script/AdaptedScriptEngine.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8ab47cfb4..449068235 100644 --- a/src/main/java/org/scijava/script/AdaptedScriptLanguage.java +++ b/src/main/java/org/scijava/script/AdaptedScriptLanguage.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,6 +35,7 @@ import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; +import org.scijava.Context; import org.scijava.plugin.PluginInfo; /** @@ -143,7 +141,7 @@ public ScriptEngine getScriptEngine() { // -- Helper methods -- private static ScriptEngineFactory findFactory(final String factoryName) { - final ScriptEngineManager manager = new ScriptEngineManager(); + final ScriptEngineManager manager = new ScriptEngineManager(Context.getClassLoader()); for (final ScriptEngineFactory factory : manager.getEngineFactories()) { for (final String name : factory.getNames()) { if (factoryName.equals(name)) return factory; diff --git a/src/main/java/org/scijava/script/AutoCompleter.java b/src/main/java/org/scijava/script/AutoCompleter.java index 220e78589..632e7498b 100644 --- a/src/main/java/org/scijava/script/AutoCompleter.java +++ b/src/main/java/org/scijava/script/AutoCompleter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e3f777d36..d3eecd426 100644 --- a/src/main/java/org/scijava/script/AutoCompletionResult.java +++ b/src/main/java/org/scijava/script/AutoCompletionResult.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b8a0e9266..fa2e6d624 100644 --- a/src/main/java/org/scijava/script/CodeGenerator.java +++ b/src/main/java/org/scijava/script/CodeGenerator.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8c2db2675..61135865c 100644 --- a/src/main/java/org/scijava/script/CodeGeneratorJava.java +++ b/src/main/java/org/scijava/script/CodeGeneratorJava.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f20e3ee25..ef3890a16 100644 --- a/src/main/java/org/scijava/script/DefaultAutoCompleter.java +++ b/src/main/java/org/scijava/script/DefaultAutoCompleter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4d2ac2050..3593d98da 100644 --- a/src/main/java/org/scijava/script/DefaultScriptHeaderService.java +++ b/src/main/java/org/scijava/script/DefaultScriptHeaderService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f6610d7f9..b0e569824 100644 --- a/src/main/java/org/scijava/script/DefaultScriptInterpreter.java +++ b/src/main/java/org/scijava/script/DefaultScriptInterpreter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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 @@ -177,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 55e2c1291..ba308b947 100644 --- a/src/main/java/org/scijava/script/DefaultScriptService.java +++ b/src/main/java/org/scijava/script/DefaultScriptService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -50,7 +47,6 @@ import org.scijava.Gateway; import org.scijava.InstantiableException; import org.scijava.MenuPath; -import org.scijava.Priority; import org.scijava.app.AppService; import org.scijava.command.CommandService; import org.scijava.log.LogService; @@ -75,7 +71,7 @@ * @author Johannes Schindelin * @author Curtis Rueden */ -@Plugin(type = Service.class, priority = Priority.HIGH) +@Plugin(type = Service.class) public class DefaultScriptService extends AbstractSingletonService implements ScriptService { @@ -196,6 +192,11 @@ public void addAlias(final String alias, final Class type) { aliasMap().put(alias, type); } + @Override + public Map> getAliases() { + return Collections.unmodifiableMap(aliasMap()); + } + @Override public synchronized Class lookupClass(final String alias) throws ScriptException @@ -226,14 +227,8 @@ public void initialize() { super.initialize(); // add scripts to the module index... only when needed! - moduleService.getIndex().addLater(new LazyObjects() { - - @Override - public Collection get() { - return scripts().values(); - } - - }); + final LazyObjects lazyScripts = () -> scripts().values(); + moduleService.getIndex().addLater(lazyScripts); } // -- Helper methods - lazy initialization -- @@ -359,7 +354,7 @@ private synchronized void initAliasMap() { * are registered with the service. */ private ScriptInfo getOrCreate(final File file) { - final ScriptInfo info = scripts().get(file); + final ScriptInfo info = scripts().get(file.getAbsolutePath()); if (info != null) return info; return new ScriptInfo(getContext(), file); } @@ -390,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 85886a494..6ec2e5260 100644 --- a/src/main/java/org/scijava/script/InvocationObject.java +++ b/src/main/java/org/scijava/script/InvocationObject.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8f6f68af5..f6d2ada7d 100644 --- a/src/main/java/org/scijava/script/ParameterObject.java +++ b/src/main/java/org/scijava/script/ParameterObject.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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..f04d344b5 --- /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 - 2025 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 0422b2aca..27a7aa7b7 100644 --- a/src/main/java/org/scijava/script/ScriptFinder.java +++ b/src/main/java/org/scijava/script/ScriptFinder.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,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; @@ -181,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 3872e1e3f..c1a3d3269 100644 --- a/src/main/java/org/scijava/script/ScriptHeader.java +++ b/src/main/java/org/scijava/script/ScriptHeader.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 25d8b08c5..c697d90f2 100644 --- a/src/main/java/org/scijava/script/ScriptHeaderService.java +++ b/src/main/java/org/scijava/script/ScriptHeaderService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ef8802b5a..a6c00d5c6 100644 --- a/src/main/java/org/scijava/script/ScriptInfo.java +++ b/src/main/java/org/scijava/script/ScriptInfo.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 782bb0d71..8faebc3c3 100644 --- a/src/main/java/org/scijava/script/ScriptInterpreter.java +++ b/src/main/java/org/scijava/script/ScriptInterpreter.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 779ca7897..4a5446292 100644 --- a/src/main/java/org/scijava/script/ScriptLanguage.java +++ b/src/main/java/org/scijava/script/ScriptLanguage.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 68fe4d6db..f3680e18b 100644 --- a/src/main/java/org/scijava/script/ScriptLanguageIndex.java +++ b/src/main/java/org/scijava/script/ScriptLanguageIndex.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -149,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 3766c56c6..b686b52a9 100644 --- a/src/main/java/org/scijava/script/ScriptModule.java +++ b/src/main/java/org/scijava/script/ScriptModule.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -105,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; } @@ -126,6 +132,13 @@ public ScriptInfo getInfo() { @Override public void run() { + // HACK: Work around code (Groovy!) assuming + // context class loader can't be null. + final ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + Thread.currentThread().setContextClassLoader(Context.getClassLoader()); + } + final ScriptEngine engine = getEngine(); final String path = getInfo().getPath(); diff --git a/src/main/java/org/scijava/script/ScriptREPL.java b/src/main/java/org/scijava/script/ScriptREPL.java index 71dc6eea0..9c1b838dd 100644 --- a/src/main/java/org/scijava/script/ScriptREPL.java +++ b/src/main/java/org/scijava/script/ScriptREPL.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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; @@ -41,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; @@ -70,7 +70,9 @@ public class ScriptREPL { @Parameter(required = false) private PluginService pluginService; - private final PrintStream out; + private final Consumer out; + + private String languagePreference; /** List of interpreter-friendly script languages. */ private List languages; @@ -85,10 +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) { + this(context, null, 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 Consumer out) + { context.inject(this); - this.out = out instanceof PrintStream ? - (PrintStream) out : new PrintStream(out); + languagePreference = language; + this.out = out; } /** @@ -124,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; } @@ -149,31 +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(); - lang(langs.get(0).getLanguageName()); + println("Have fun!"); + println(); + } + if (!langs.isEmpty()) { + if (languagePreference != null) selectPreferredLanguage(langs); + else lang(langs.get(0)); } - else if (!langs.isEmpty()) lang(langs.get(0)); populateBindings(interpreter.getBindings()); } + private void selectPreferredLanguage(List langs) { + 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() ? "> " : "\\ "); } /** @@ -199,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; } @@ -223,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. */ @@ -263,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()); } /** @@ -285,7 +340,7 @@ public void lang(final ScriptLanguage language) { copyBindings(interpreter, newInterpreter); } catch (final Throwable t) { - t.printStackTrace(out); + printStackTrace(t); } interpreter = newInterpreter; } @@ -304,7 +359,7 @@ public void langs() { public void debug() { debug = !debug; - out.println("debug mode -> " + debug); + println("debug mode -> " + debug); } // -- Main method -- @@ -313,8 +368,15 @@ public static void main(final String... args) throws Exception { // make a SciJava application context final Context context = new Context(); - // create the script interpreter - final ScriptREPL scriptCLI = new ScriptREPL(context); + // see if we have a preferred language + // and create the script interpreter + final ScriptREPL scriptCLI; + if(args.length > 0) { + final String preference = args[0]; + scriptCLI = new ScriptREPL(context, preference); + } else { + scriptCLI = new ScriptREPL(context); + } // start the REPL scriptCLI.loop(); @@ -379,13 +441,18 @@ private List gateways() { gateways.add(gateway); } catch (final Throwable t) { - t.printStackTrace(out); + printStackTrace(t); } } return gateways; } private String serviceName(final Service service) { + final PluginInfo info = service.getInfo(); + final String pluginName = info == null ? null : info.getName(); + // Name was explicitly given in the @Plugin annotation. + if (pluginName != null && !pluginName.isEmpty()) return pluginName; + // No name was given; synthesize one from the class name. final String serviceName = service.getClass().getSimpleName(); final String shortName = lowerCamelCase( serviceName.replaceAll("^(Default)?(.*)Service$", "$2")); @@ -399,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; @@ -413,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 type) { /** TODO */ void addAlias(String alias, Class type); + /** TODO */ + Map> getAliases(); + /** TODO */ Class lookupClass(String typeName) throws ScriptException; diff --git a/src/main/java/org/scijava/script/console/RunScriptArgument.java b/src/main/java/org/scijava/script/console/RunScriptArgument.java index f8b99c3b9..df7335169 100644 --- a/src/main/java/org/scijava/script/console/RunScriptArgument.java +++ b/src/main/java/org/scijava/script/console/RunScriptArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/io/ScriptIOPlugin.java b/src/main/java/org/scijava/script/io/ScriptIOPlugin.java index d85817af8..dec94b517 100644 --- a/src/main/java/org/scijava/script/io/ScriptIOPlugin.java +++ b/src/main/java/org/scijava/script/io/ScriptIOPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,8 +33,9 @@ import org.scijava.io.AbstractIOPlugin; import org.scijava.io.IOPlugin; +import org.scijava.io.location.FileLocation; +import org.scijava.io.location.Location; import org.scijava.plugin.Parameter; -import org.scijava.plugin.Plugin; import org.scijava.script.ScriptService; /** @@ -46,7 +44,6 @@ * @author Curtis Rueden * @see ScriptService */ -@Plugin(type = IOPlugin.class) public class ScriptIOPlugin extends AbstractIOPlugin { @Parameter(required = false) @@ -60,13 +57,16 @@ public Class getDataType() { } @Override - public boolean supportsOpen(final String source) { + public boolean supportsOpen(final Location source) { if (scriptService == null) return false; // no service for opening scripts - return scriptService.canHandleFile(source); + // TODO: Update ScriptService to use Location instead of File. + if (!(source instanceof FileLocation)) return false; + final FileLocation loc = (FileLocation) source; + return scriptService.canHandleFile(loc.getFile()); } @Override - public String open(final String source) throws IOException { + public String open(final Location source) throws IOException { if (scriptService == null) return null; // no service for opening scripts // TODO: Use the script service to open the file in the script editor. return null; diff --git a/src/main/java/org/scijava/script/process/DefaultScriptProcessorService.java b/src/main/java/org/scijava/script/process/DefaultScriptProcessorService.java index 1978295b4..99fd73812 100644 --- a/src/main/java/org/scijava/script/process/DefaultScriptProcessorService.java +++ b/src/main/java/org/scijava/script/process/DefaultScriptProcessorService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/DirectiveScriptProcessor.java b/src/main/java/org/scijava/script/process/DirectiveScriptProcessor.java index a7cdbba47..4b1fe8c34 100644 --- a/src/main/java/org/scijava/script/process/DirectiveScriptProcessor.java +++ b/src/main/java/org/scijava/script/process/DirectiveScriptProcessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/ParameterScriptProcessor.java b/src/main/java/org/scijava/script/process/ParameterScriptProcessor.java index c1a3170e8..d3988e9ef 100644 --- a/src/main/java/org/scijava/script/process/ParameterScriptProcessor.java +++ b/src/main/java/org/scijava/script/process/ParameterScriptProcessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -132,7 +129,7 @@ public void begin(final ScriptInfo scriptInfo) { @Override public String process(final String line) { - // parse new-style parameters starting with @# anywhere in the script. + // parse new-style parameters starting with #@ anywhere in the script. if (line.matches("^#@.*")) { final int at = line.indexOf('@'); return process(line, line.substring(at + 1)); @@ -143,7 +140,9 @@ public String process(final String line) { // NB: Check if line contains an '@' with no prior alphameric // characters. This assumes that only non-alphanumeric characters can // be used as comment line markers. - if (line.matches("^[^\\w]*@.*")) { + // NB: In addition, to allow for commented-out new-style parameters, we exclude + // lines that have the new-style #@ preceded by non-alphanumeric characters. + if (line.matches("^[^\\w]*[^\\w#]@.*")) { final int at = line.indexOf('@'); return process(line, line.substring(at + 1)); } @@ -270,6 +269,7 @@ private void assignAttribute(final DefaultMutableModuleItem item, else if (is(k, "max")) item.setMaximumValue(as(v, item.getType())); else if (is(k, "min")) item.setMinimumValue(as(v, item.getType())); else if (is(k, "name")) item.setName(as(v, String.class)); + else if (is(k, "autoFill")) item.setAutoFill(as(v, boolean.class)); else if (is(k, "persist")) item.setPersisted(as(v, boolean.class)); else if (is(k, "persistKey")) item.setPersistKey(as(v, String.class)); else if (is(k, "required")) item.setRequired(as(v, boolean.class)); diff --git a/src/main/java/org/scijava/script/process/ScriptCallback.java b/src/main/java/org/scijava/script/process/ScriptCallback.java index 5d060704f..eaedad35c 100644 --- a/src/main/java/org/scijava/script/process/ScriptCallback.java +++ b/src/main/java/org/scijava/script/process/ScriptCallback.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/ScriptDirectiveScriptProcessor.java b/src/main/java/org/scijava/script/process/ScriptDirectiveScriptProcessor.java index eefbb4a76..40b905ede 100644 --- a/src/main/java/org/scijava/script/process/ScriptDirectiveScriptProcessor.java +++ b/src/main/java/org/scijava/script/process/ScriptDirectiveScriptProcessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,6 +35,7 @@ import org.scijava.Priority; import org.scijava.log.LogService; import org.scijava.module.ModuleInfo; +import org.scijava.module.ModuleService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; @@ -95,7 +93,7 @@ * * @author Curtis Rueden */ -@Plugin(type = ScriptProcessor.class) +@Plugin(type = ScriptProcessor.class, priority=Priority.HIGH) public class ScriptDirectiveScriptProcessor extends DirectiveScriptProcessor { public ScriptDirectiveScriptProcessor() { @@ -104,6 +102,9 @@ public ScriptDirectiveScriptProcessor() { @Parameter private LogService log; + + @Parameter + private ModuleService moduleService; // -- Internal DirectiveScriptProcessor methods -- @@ -114,6 +115,7 @@ protected String process(final String directive, for (final String k : attrs.keySet()) { assignAttribute(k == null ? "name" : k, attrs.get(k)); } + moduleService.addModule(info()); // TODO how to handle duplicate names? return ""; } diff --git a/src/main/java/org/scijava/script/process/ScriptProcessor.java b/src/main/java/org/scijava/script/process/ScriptProcessor.java index 11bb9645a..edeec681b 100644 --- a/src/main/java/org/scijava/script/process/ScriptProcessor.java +++ b/src/main/java/org/scijava/script/process/ScriptProcessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 66a482476..a73b4ebb7 100644 --- a/src/main/java/org/scijava/script/process/ScriptProcessorService.java +++ b/src/main/java/org/scijava/script/process/ScriptProcessorService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1d93df16b..6e3991590 100644 --- a/src/main/java/org/scijava/script/process/ShebangScriptProcessor.java +++ b/src/main/java/org/scijava/script/process/ShebangScriptProcessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 02df88c75..d016431ee 100644 --- a/src/main/java/org/scijava/script/run/ScriptCodeRunner.java +++ b/src/main/java/org/scijava/script/run/ScriptCodeRunner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0a5e7c631..ce04e97e7 100644 --- a/src/main/java/org/scijava/service/AbstractService.java +++ b/src/main/java/org/scijava/service/AbstractService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5887eec55..eb311bd80 100644 --- a/src/main/java/org/scijava/service/SciJavaService.java +++ b/src/main/java/org/scijava/service/SciJavaService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3260f6205..13f2c1081 100644 --- a/src/main/java/org/scijava/service/Service.java +++ b/src/main/java/org/scijava/service/Service.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 22e9503a7..3b06233ca 100644 --- a/src/main/java/org/scijava/service/ServiceHelper.java +++ b/src/main/java/org/scijava/service/ServiceHelper.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -65,7 +62,7 @@ public class ServiceHelper extends AbstractContextual { * Classes to scan when searching for dependencies. Data structure is a map * with keys being relevant classes, and values being associated priorities. */ - private final Map, Double> classPoolMap; + private final Map, PluginInfo> classPoolMap; /** Classes to scan when searching for dependencies, sorted by priority. */ private final List> classPoolList; @@ -303,9 +300,10 @@ private S createServiceRecursively(final Class c) final S service = c.newInstance(); service.setContext(getContext()); - // propagate priority if known - final Double priority = classPoolMap.get(c); - if (priority != null) service.setPriority(priority); + // propagate plugin metadata and priority if known + final PluginInfo info = classPoolMap.get(c); + service.setInfo(info); + if (info != null) service.setPriority(info.getPriority()); // NB: If there are any @EventHandler annotated methods, we treat the // EventService as a required dependency, _unless_ there is also an @@ -358,7 +356,7 @@ private S createServiceRecursively(final Class c) /** Asks the plugin index for all available service implementations. */ private void findServiceClasses( - final Map, Double> serviceMap, + final Map, PluginInfo> serviceMap, final List> serviceList) { // ask the plugin index for the (sorted) list of available services @@ -368,8 +366,7 @@ private void findServiceClasses( for (final PluginInfo info : services) { try { final Class c = info.loadClass(); - final double priority = info.getPriority(); - serviceMap.put(c, priority); + serviceMap.put(c, info); serviceList.add(c); } catch (final Throwable e) { diff --git a/src/main/java/org/scijava/service/ServiceIndex.java b/src/main/java/org/scijava/service/ServiceIndex.java index e512c2a0f..f926883a0 100644 --- a/src/main/java/org/scijava/service/ServiceIndex.java +++ b/src/main/java/org/scijava/service/ServiceIndex.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8c06ba6d0..fe0109129 100644 --- a/src/main/java/org/scijava/service/event/ServicesLoadedEvent.java +++ b/src/main/java/org/scijava/service/event/ServicesLoadedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2a4d8ab4c..8131b6bc2 100644 --- a/src/main/java/org/scijava/startup/DefaultStartupService.java +++ b/src/main/java/org/scijava/startup/DefaultStartupService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8f1e56f47..35e747b39 100644 --- a/src/main/java/org/scijava/startup/StartupService.java +++ b/src/main/java/org/scijava/startup/StartupService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8042f511e..048f7b773 100644 --- a/src/main/java/org/scijava/task/DefaultTask.java +++ b/src/main/java/org/scijava/task/DefaultTask.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,11 +36,35 @@ import org.scijava.thread.ThreadService; /** - * Default implementation of {@link Task}. It launches code via the linked - * {@link ThreadService}, and reports status updates via the linked - * {@link EventService}. + * 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}. + * 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. + * In the asynchronous case, upon task cancellation ({@link Task#cancel(String)} call), + * the runnable associated to the ThreadService is attempted to be stopped + * 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()}, + * 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} + * to subscribers (with the EventService). + * 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 + * @author Nicolas Chiaruttini */ public class DefaultTask implements Task { @@ -54,6 +75,7 @@ public class DefaultTask implements Task { private boolean canceled; private String cancelReason; + volatile boolean isDone = false; private String status; private long step; @@ -61,9 +83,11 @@ public class DefaultTask implements Task { private String name; + private Runnable cancelCallBack; + /** * Creates a new task. - * + * * @param threadService Service to use for launching the task in its own * thread. Required. * @param eventService Service to use for reporting status updates as @@ -75,24 +99,40 @@ public DefaultTask(final ThreadService threadService, { this.threadService = threadService; this.eventService = eventService; + cancelCallBack = this::defaultCancelCallback; } // -- Task methods -- + // - Asynchronous @Override public void run(final Runnable r) { if (r == null) throw new NullPointerException(); future(r); } + // - Asynchronous @Override public void waitFor() throws InterruptedException, ExecutionException { future().get(); } + // - Synchronous + @Override + public void start() { + fireTaskEvent(); + } + + // - Synchronous + @Override + public void finish() { + isDone = true; + fireTaskEvent(); + } + @Override public boolean isDone() { - return future != null && future.isDone(); + return (isDone) || (future != null && future.isDone()); } @Override @@ -139,6 +179,24 @@ public boolean isCanceled() { public void cancel(final String reason) { canceled = true; cancelReason = reason; + if (cancelCallBack != null) cancelCallBack.run(); + fireTaskEvent(); + } + + void defaultCancelCallback() { + if (future != null) { + isDone = future.cancel(true); + } + } + + @Override + public void setCancelCallBack(Runnable r) { + this.cancelCallBack = r; + } + + @Override + public Runnable getCancelCallBack() { + return this.cancelCallBack; } @Override @@ -172,7 +230,17 @@ private Future future(final Runnable r) { private synchronized void initFuture(final Runnable r) { if (future != null) return; if (r == null) throw new IllegalArgumentException("Must call run first"); - future = threadService.run(r); + future = threadService.run(() -> { + try { + fireTaskEvent(); // Triggers an event just before the task is executed + r.run(); + } + finally { + isDone = true; + fireTaskEvent(); // Triggers an event just after the task has + // successfully completed or failed + } + }); } private void fireTaskEvent() { diff --git a/src/main/java/org/scijava/task/DefaultTaskService.java b/src/main/java/org/scijava/task/DefaultTaskService.java index e99edfa3a..147fd0eec 100644 --- a/src/main/java/org/scijava/task/DefaultTaskService.java +++ b/src/main/java/org/scijava/task/DefaultTaskService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 958ec8d07..1e8004e53 100644 --- a/src/main/java/org/scijava/task/Task.java +++ b/src/main/java/org/scijava/task/Task.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,19 +37,39 @@ /** * A self-aware job which reports its status and progress as it runs. * - * @author Curtis Rueden + * There are two ways to use a Task object: + * - A job can be run asynchronously by using {@link Task#run(Runnable)}, and + * can report its progression from within the Runnable. + * + * - A {@link Task} object can simply be used to report in a synchronous manner + * the progression of a piece of code. In the case of synchronous reporting, + * the job is considered started when {@link Task#start()} is called and + * finished when {@link Task#finish()} is called. A finished job can be finished + * either because it is done or because it has been cancelled. + * + * A cancel callback can be set with {@link Task#setCancelCallBack(Runnable)}. + * The runnable argument will be executed in the case of an external event + * requesting a cancellation of the task - typically, if a user clicks + * a cancel button on the GUI, task.cancel("User cancellation requested") will + * be called. As a result, the task implementors should run the callback. + * This callback can be used to make the task aware that a cancellation + * has been requested, and should proceed to stop its execution. + * + * See also {@link TaskService}, {@link DefaultTask} + * + * @author Curtis Rueden, Nicolas Chiaruttini */ public interface Task extends Cancelable, Named { /** - * Starts running the task. + * Starts running the task - asynchronous job * * @throws IllegalStateException if the task was already started. */ void run(Runnable r); /** - * Waits for the task to complete. + * Waits for the task to complete - asynchronous job * * @throws IllegalStateException if {@link #run} has not been called yet. * @throws InterruptedException if the task is interrupted. @@ -60,6 +77,16 @@ public interface Task extends Cancelable, Named { */ void waitFor() throws InterruptedException, ExecutionException; + /** + * reports that the task is started - synchronous job + */ + default void start() {} + + /** + * reports that the task is finished - synchronous job + */ + default void finish() {} + /** Checks whether the task has completed. */ boolean isDone(); @@ -105,4 +132,23 @@ public interface Task extends Cancelable, Named { * @see #getProgressMaximum() */ void setProgressMaximum(long max); + + /** + * If the task is cancelled (external call to {@link Task#cancel(String)}), + * the input runnable argument should be executed by task implementors. + * + * @param runnable : should be executed if this task is cancelled through + * {@link Task#cancel(String)} + */ + default void setCancelCallBack(Runnable runnable) {} + + /** + * Returns the current cancel callback runnable, This can be used to + * concatenate callbacks in order, for instance, to ask for a user + * confirmation before cancelling the task + */ + default Runnable getCancelCallBack() { + return () -> {}; + } + } diff --git a/src/main/java/org/scijava/task/TaskService.java b/src/main/java/org/scijava/task/TaskService.java index 774f2ae98..dfe5c0ffd 100644 --- a/src/main/java/org/scijava/task/TaskService.java +++ b/src/main/java/org/scijava/task/TaskService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a8f3a02dd..83a5d662c 100644 --- a/src/main/java/org/scijava/task/event/TaskEvent.java +++ b/src/main/java/org/scijava/task/event/TaskEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3244499c7..c375f6994 100644 --- a/src/main/java/org/scijava/test/TestUtils.java +++ b/src/main/java/org/scijava/test/TestUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c02394f10..766cb0874 100644 --- a/src/main/java/org/scijava/text/AbstractTextFormat.java +++ b/src/main/java/org/scijava/text/AbstractTextFormat.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,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 34ef2479a..211fd25f2 100644 --- a/src/main/java/org/scijava/text/DefaultTextService.java +++ b/src/main/java/org/scijava/text/DefaultTextService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -62,17 +59,13 @@ public final class DefaultTextService extends @Override public String open(final File file) throws IOException { - // This routine is from: http://stackoverflow.com/a/326440 - final FileInputStream stream = new FileInputStream(file); - try { + // This routine is from: https://stackoverflow.com/a/326440 + try (final FileInputStream stream = new FileInputStream(file)) { final FileChannel fc = stream.getChannel(); final MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); return Charset.defaultCharset().decode(bb).toString(); } - finally { - stream.close(); - } } @Override diff --git a/src/main/java/org/scijava/text/TextFormat.java b/src/main/java/org/scijava/text/TextFormat.java index 6e483d3b1..2ef04da75 100644 --- a/src/main/java/org/scijava/text/TextFormat.java +++ b/src/main/java/org/scijava/text/TextFormat.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -66,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 16b18d1c6..5149b2a38 100644 --- a/src/main/java/org/scijava/text/TextService.java +++ b/src/main/java/org/scijava/text/TextService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 new file mode 100644 index 000000000..21937f384 --- /dev/null +++ b/src/main/java/org/scijava/text/io/DefaultTextIOService.java @@ -0,0 +1,43 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.text.io; + +import org.scijava.io.AbstractTypedIOService; +import org.scijava.plugin.Plugin; +import org.scijava.service.Service; + +/** + * Default {@link TextIOService} implementation for opening and saving text data + * + * @author Deborah Schmidt + */ +@Plugin(type = Service.class) +public class DefaultTextIOService extends AbstractTypedIOService implements TextIOService { +} diff --git a/src/main/java/org/scijava/text/io/TextIOPlugin.java b/src/main/java/org/scijava/text/io/TextIOPlugin.java index 03b090046..3e3d20efd 100644 --- a/src/main/java/org/scijava/text/io/TextIOPlugin.java +++ b/src/main/java/org/scijava/text/io/TextIOPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,12 +29,13 @@ package org.scijava.text.io; -import java.io.File; import java.io.IOException; import org.scijava.Priority; import org.scijava.io.AbstractIOPlugin; import org.scijava.io.IOPlugin; +import org.scijava.io.location.FileLocation; +import org.scijava.io.location.Location; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; import org.scijava.text.TextService; @@ -62,15 +60,19 @@ public Class getDataType() { } @Override - public boolean supportsOpen(final String source) { + public boolean supportsOpen(final Location source) { if (textService == null) return false; // no service for opening text files - return textService.supports(new File(source)); + if (!(source instanceof FileLocation)) return false; + final FileLocation loc = (FileLocation) source; + return textService.supports(loc.getFile()); } @Override - public String open(final String source) throws IOException { + public String open(final Location source) throws IOException { if (textService == null) return null; // no service for opening text files - return textService.asHTML(new File(source)); + if (!(source instanceof FileLocation)) throw new IllegalArgumentException(); + final FileLocation loc = (FileLocation) source; + return textService.asHTML(loc.getFile()); } } diff --git a/src/main/java/org/scijava/text/io/TextIOService.java b/src/main/java/org/scijava/text/io/TextIOService.java new file mode 100644 index 000000000..ed48ab424 --- /dev/null +++ b/src/main/java/org/scijava/text/io/TextIOService.java @@ -0,0 +1,40 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.text.io; + +import org.scijava.io.TypedIOService; + +/** + * {@link TypedIOService} for opening and saving text data + * + * @author Deborah Schmidt + */ +public interface TextIOService extends TypedIOService { +} diff --git a/src/main/java/org/scijava/thread/DefaultThreadService.java b/src/main/java/org/scijava/thread/DefaultThreadService.java index 34dac1f10..f34c38a6a 100644 --- a/src/main/java/org/scijava/thread/DefaultThreadService.java +++ b/src/main/java/org/scijava/thread/DefaultThreadService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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; @@ -61,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<>(); @@ -162,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); + } } } } @@ -176,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 -- @@ -190,14 +209,9 @@ private synchronized ExecutorService executor(final String id) { if (disposed) return null; if (queues == null) queues = new HashMap<>(); if (!queues.containsKey(id)) { - final ThreadFactory factory = new ThreadFactory() { - - @Override - public Thread newThread(final Runnable r) { - final String threadName = contextThreadPrefix() + id; - return new Thread(r, threadName); - } - + final ThreadFactory factory = r -> { + final String threadName = contextThreadPrefix() + id; + return new Thread(r, threadName); }; final ExecutorService queue = Executors.newSingleThreadExecutor(factory); queues.put(id, queue); @@ -212,34 +226,28 @@ private synchronized void initExecutor() { private Runnable wrap(final Runnable r) { final Thread parent = Thread.currentThread(); - return new Runnable() { - @Override - public void run() { - final Thread thread = Thread.currentThread(); - try { - if (parent != thread) parents.put(thread, parent); - r.run(); - } - finally { - if (parent != thread) parents.remove(thread); - } + return () -> { + final Thread thread = Thread.currentThread(); + try { + if (parent != thread) parents.put(thread, parent); + r.run(); + } + finally { + if (parent != thread) parents.remove(thread); } }; } private Callable wrap(final Callable c) { final Thread parent = Thread.currentThread(); - return new Callable() { - @Override - public V call() throws Exception { - final Thread thread = Thread.currentThread(); - try { - if (parent != thread) parents.put(thread, parent); - return c.call(); - } - finally { - if (parent != thread) parents.remove(thread); - } + return () -> { + final Thread thread = Thread.currentThread(); + try { + if (parent != thread) parents.put(thread, parent); + return c.call(); + } + finally { + if (parent != thread) parents.remove(thread); } }; } diff --git a/src/main/java/org/scijava/thread/ThreadService.java b/src/main/java/org/scijava/thread/ThreadService.java index e33011885..b809a9a4b 100644 --- a/src/main/java/org/scijava/thread/ThreadService.java +++ b/src/main/java/org/scijava/thread/ThreadService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f233701ba..e83ada645 100644 --- a/src/main/java/org/scijava/tool/AbstractTool.java +++ b/src/main/java/org/scijava/tool/AbstractTool.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3b9c6cd32..4222b14b0 100644 --- a/src/main/java/org/scijava/tool/CustomDrawnTool.java +++ b/src/main/java/org/scijava/tool/CustomDrawnTool.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cb714e30f..d7d653399 100644 --- a/src/main/java/org/scijava/tool/DefaultToolService.java +++ b/src/main/java/org/scijava/tool/DefaultToolService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 508c35b16..c2e858e00 100644 --- a/src/main/java/org/scijava/tool/DummyTool.java +++ b/src/main/java/org/scijava/tool/DummyTool.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6e2c26d27..ff4b83a40 100644 --- a/src/main/java/org/scijava/tool/IconDrawer.java +++ b/src/main/java/org/scijava/tool/IconDrawer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 48b5b2ae8..02be9b223 100644 --- a/src/main/java/org/scijava/tool/IconService.java +++ b/src/main/java/org/scijava/tool/IconService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8e32d696b..c2a0d00f0 100644 --- a/src/main/java/org/scijava/tool/Tool.java +++ b/src/main/java/org/scijava/tool/Tool.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 29065b2f7..020a3e891 100644 --- a/src/main/java/org/scijava/tool/ToolService.java +++ b/src/main/java/org/scijava/tool/ToolService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 70df3662f..6df9190ef 100644 --- a/src/main/java/org/scijava/tool/event/ToolActivatedEvent.java +++ b/src/main/java/org/scijava/tool/event/ToolActivatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 9eab6bd6c..78569c9ea 100644 --- a/src/main/java/org/scijava/tool/event/ToolDeactivatedEvent.java +++ b/src/main/java/org/scijava/tool/event/ToolDeactivatedEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1ea60d802..85aed4d60 100644 --- a/src/main/java/org/scijava/tool/event/ToolEvent.java +++ b/src/main/java/org/scijava/tool/event/ToolEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0b6681e37..ff21f7bd7 100644 --- a/src/main/java/org/scijava/ui/ARGBPlane.java +++ b/src/main/java/org/scijava/ui/ARGBPlane.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6b078bdb5..a31e09d59 100644 --- a/src/main/java/org/scijava/ui/AbstractInputHarvesterPlugin.java +++ b/src/main/java/org/scijava/ui/AbstractInputHarvesterPlugin.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 96505d1ff..32d324ef1 100644 --- a/src/main/java/org/scijava/ui/AbstractUIInputWidget.java +++ b/src/main/java/org/scijava/ui/AbstractUIInputWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -80,12 +77,7 @@ public void refreshWidget() { // on the EDT. if (ui().requiresEDT()) { try { - threadService.invoke(new Runnable() { - @Override - public void run() { - doRefresh(); - } - }); + threadService.invoke(() -> doRefresh()); } catch (InterruptedException e) { log.error("Interrupted while refresh widget: " + getClass(), e); diff --git a/src/main/java/org/scijava/ui/AbstractUserInterface.java b/src/main/java/org/scijava/ui/AbstractUserInterface.java index 0e429808e..d1b91e527 100644 --- a/src/main/java/org/scijava/ui/AbstractUserInterface.java +++ b/src/main/java/org/scijava/ui/AbstractUserInterface.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -82,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 ddbde1e27..57fc6083f 100644 --- a/src/main/java/org/scijava/ui/ApplicationFrame.java +++ b/src/main/java/org/scijava/ui/ApplicationFrame.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 49f2b6d64..2385868c5 100644 --- a/src/main/java/org/scijava/ui/Arrangeable.java +++ b/src/main/java/org/scijava/ui/Arrangeable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 fb81cb57d..331f50861 100644 --- a/src/main/java/org/scijava/ui/CloseConfirmable.java +++ b/src/main/java/org/scijava/ui/CloseConfirmable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 49368efc8..5d4d7299d 100644 --- a/src/main/java/org/scijava/ui/DefaultUIService.java +++ b/src/main/java/org/scijava/ui/DefaultUIService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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; @@ -119,6 +118,17 @@ 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 + * #isHeadless()} matches the global JVM headless state defined by {@code + * java.awt.headless}. + */ + private boolean forceHeadless; + private boolean activationInvocationPending = false; // -- UIService methods -- @@ -137,14 +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 noUIsAvailableException(); - 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); } @@ -154,44 +162,56 @@ 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) throw noUIsAvailableException(); - return ui.isVisible(); + return activeUI().isVisible(); } @Override public boolean isVisible(final String name) { - final UserInterface ui = uiMap().get(name); - if (ui == null) { - throw new IllegalArgumentException("No such user interface: " + name); - } - return ui.isVisible(); + final UserInterface ui = getUI(name); + return ui != null && ui.isVisible(); } @Override public void setHeadless(final boolean headless) { - System.setProperty("java.awt.headless", String.valueOf(headless)); + forceHeadless = headless; } @Override public boolean isHeadless() { - return 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); } @@ -235,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 @@ -300,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 @@ -436,7 +449,10 @@ public void run() { } @EventHandler - protected void onEvent(@SuppressWarnings("unused") final AppQuitEvent event) { + protected synchronized void onEvent( + @SuppressWarnings("unused") final AppQuitEvent event) + { + if (!initialized) return; for (final UserInterface ui : getVisibleUIs()) { ui.saveLocation(); } @@ -531,9 +547,16 @@ private String getTitle() { return appService.getApp().getTitle(); } - private IllegalStateException noUIsAvailableException() { - return new IllegalStateException("No UIs available. " + - "Please add a component containing a UIPlugin " + - "(e.g., scijava-ui-swing) to your class-path."); + /** 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 710d440c4..11aa766f4 100644 --- a/src/main/java/org/scijava/ui/Desktop.java +++ b/src/main/java/org/scijava/ui/Desktop.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d0e0ec607..fc59a3c05 100644 --- a/src/main/java/org/scijava/ui/DialogPrompt.java +++ b/src/main/java/org/scijava/ui/DialogPrompt.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6a8971898..c18810629 100644 --- a/src/main/java/org/scijava/ui/FileListPreprocessor.java +++ b/src/main/java/org/scijava/ui/FileListPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2bb916e29..909e84c06 100644 --- a/src/main/java/org/scijava/ui/FilePreprocessor.java +++ b/src/main/java/org/scijava/ui/FilePreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ea09442f9..19ad8acb8 100644 --- a/src/main/java/org/scijava/ui/StatusBar.java +++ b/src/main/java/org/scijava/ui/StatusBar.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4bbd7e490..d897285e7 100644 --- a/src/main/java/org/scijava/ui/SystemClipboard.java +++ b/src/main/java/org/scijava/ui/SystemClipboard.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f4ef6f875..b14ceb0fa 100644 --- a/src/main/java/org/scijava/ui/ToolBar.java +++ b/src/main/java/org/scijava/ui/ToolBar.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b55dffbb2..36fd91147 100644 --- a/src/main/java/org/scijava/ui/UIPreprocessor.java +++ b/src/main/java/org/scijava/ui/UIPreprocessor.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +59,12 @@ public void process(final Module module) { if (ui == null) return; // no default UI for (final ModuleItem input : module.getInfo().inputs()) { - if (!input.isAutoFill()) continue; // cannot auto-fill this input + if (!input.isAutoFill()) continue; // skip unfillable inputs + if (module.isInputResolved(input.getName())) continue; // skip resolved inputs final Class type = input.getType(); - if (type.isAssignableFrom(ui.getClass())) { + if (UserInterface.class.isAssignableFrom(type) && // + type.isAssignableFrom(ui.getClass())) + { // input is a compatible UI final String name = input.getName(); module.setInput(name, ui); diff --git a/src/main/java/org/scijava/ui/UIService.java b/src/main/java/org/scijava/ui/UIService.java index 9b711bd05..84f4b23ef 100644 --- a/src/main/java/org/scijava/ui/UIService.java +++ b/src/main/java/org/scijava/ui/UIService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -104,10 +101,33 @@ public interface UIService extends SciJavaService { /** Gets whether the UI with the given name or class name is visible. */ boolean isVisible(String name); - /** Sets whether the application is running in headless mode (no UI). */ + /** + * Sets whether the application should run in headless mode (no UI). + *

+ * Note that if the system itself is headless—which can be detected via + * the {@code java.awt.headless} system property or by 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. + *

+ *

+ * But if the system itself is not headless, calling + * {@code setHeadless(true)} will force {@link #isHeadless()} to return true, + * instructing the application to behave in a headless manner insofar as it + * can. + *

+ */ 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 385df24d8..5133008eb 100644 --- a/src/main/java/org/scijava/ui/UserInterface.java +++ b/src/main/java/org/scijava/ui/UserInterface.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,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. @@ -162,9 +160,12 @@ DialogPrompt dialogPrompt(String message, String title, */ default File chooseFile(final File file, final String style) { final String title; - if (style.equals(FileWidget.DIRECTORY_STYLE)) title = "Choose a directory"; - else if (style.equals(FileWidget.OPEN_STYLE)) title = "Open"; - else if (style.equals(FileWidget.SAVE_STYLE)) title = "Save"; + // style can be a string with multiple comma-separated keywords + if (style == null) title = "Choose a file"; + 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 bc029ea35..abe9177e7 100644 --- a/src/main/java/org/scijava/ui/console/AbstractConsolePane.java +++ b/src/main/java/org/scijava/ui/console/AbstractConsolePane.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7f373bf10..c2214bd61 100644 --- a/src/main/java/org/scijava/ui/console/ConsolePane.java +++ b/src/main/java/org/scijava/ui/console/ConsolePane.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 97551d667..ab4eea39e 100644 --- a/src/main/java/org/scijava/ui/console/HeadlessArgument.java +++ b/src/main/java/org/scijava/ui/console/HeadlessArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 206899067..b07e618e9 100644 --- a/src/main/java/org/scijava/ui/console/ShowUIArgument.java +++ b/src/main/java/org/scijava/ui/console/ShowUIArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 adb428492..1622d1e0d 100644 --- a/src/main/java/org/scijava/ui/console/UIArgument.java +++ b/src/main/java/org/scijava/ui/console/UIArgument.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 643bcbfba..fe0b3da6a 100644 --- a/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropData.java +++ b/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropData.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 15f675082..cb25e57ce 100644 --- a/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/AbstractDragAndDropHandler.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8a0012b07..1c278a394 100644 --- a/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropData.java +++ b/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropData.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0c7355dd7..e18db980b 100644 --- a/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropService.java +++ b/src/main/java/org/scijava/ui/dnd/DefaultDragAndDropService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 cbad90cde..4dd73dbd0 100644 --- a/src/main/java/org/scijava/ui/dnd/DragAndDropData.java +++ b/src/main/java/org/scijava/ui/dnd/DragAndDropData.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6f65c0a73..1b793784c 100644 --- a/src/main/java/org/scijava/ui/dnd/DragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/DragAndDropHandler.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c52b28565..f1de3ddb9 100644 --- a/src/main/java/org/scijava/ui/dnd/DragAndDropService.java +++ b/src/main/java/org/scijava/ui/dnd/DragAndDropService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e6116de21..62684957f 100644 --- a/src/main/java/org/scijava/ui/dnd/FileDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/FileDragAndDropHandler.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +36,7 @@ import org.scijava.display.Display; import org.scijava.display.DisplayService; import org.scijava.io.IOService; +import org.scijava.io.location.FileLocation; import org.scijava.log.LogService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; @@ -71,7 +69,8 @@ public boolean supports(final File file) { if (!super.supports(file)) return false; // verify that the file can be opened somehow - return ioService.getOpener(file.getAbsolutePath()) != null; + final FileLocation loc = new FileLocation(file); + return ioService.getOpener(loc) != null; } @Override @@ -81,13 +80,12 @@ public boolean drop(final File file, final Display display) { if (file == null) return true; // trivial case // load the data - final String filename = file.getAbsolutePath(); final Object data; try { - data = ioService.open(filename); + data = ioService.open(new FileLocation(file)); } catch (final IOException exc) { - if (log != null) log.error("Error opening file: " + filename, exc); + if (log != null) log.error("Error opening file: " + file, exc); return false; } diff --git a/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java b/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java index 7e92f190e..64febfa13 100644 --- a/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/ListDragAndDropHandler.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2600b161d..4d7f01307 100644 --- a/src/main/java/org/scijava/ui/dnd/MIMEType.java +++ b/src/main/java/org/scijava/ui/dnd/MIMEType.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c3e49ee08..5298fc946 100644 --- a/src/main/java/org/scijava/ui/dnd/ScriptFileDragAndDropHandler.java +++ b/src/main/java/org/scijava/ui/dnd/ScriptFileDragAndDropHandler.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 429f6903a..83b15db9e 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragAndDropEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragAndDropEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d89ef6ef9..5c93dff04 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragEnterEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragEnterEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 57a93a2bb..0576666e8 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragExitEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragExitEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c2a3ff8b2..df28afbb5 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DragOverEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DragOverEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f91dada1b..d1000d5d3 100644 --- a/src/main/java/org/scijava/ui/dnd/event/DropEvent.java +++ b/src/main/java/org/scijava/ui/dnd/event/DropEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2a03183dd..8a0892f1a 100644 --- a/src/main/java/org/scijava/ui/event/UIEvent.java +++ b/src/main/java/org/scijava/ui/event/UIEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1cd8b54d5..957efb500 100644 --- a/src/main/java/org/scijava/ui/event/UIShownEvent.java +++ b/src/main/java/org/scijava/ui/event/UIShownEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 62576cc9a..af6b6c902 100644 --- a/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java +++ b/src/main/java/org/scijava/ui/headless/HeadlessDisplayViewer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8b70fd54e..654b42e7f 100644 --- a/src/main/java/org/scijava/ui/headless/HeadlessUI.java +++ b/src/main/java/org/scijava/ui/headless/HeadlessUI.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 90e4105f6..3c55c9cd2 100644 --- a/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java +++ b/src/main/java/org/scijava/ui/headlessUI/HeadlessUI.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d949a3312..3bda15d67 100644 --- a/src/main/java/org/scijava/ui/viewer/AbstractDisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/AbstractDisplayViewer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5edabe84f..691b42687 100644 --- a/src/main/java/org/scijava/ui/viewer/DisplayPanel.java +++ b/src/main/java/org/scijava/ui/viewer/DisplayPanel.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d7ac3f89b..eb439e8f6 100644 --- a/src/main/java/org/scijava/ui/viewer/DisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/DisplayViewer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d170758fe..14654e681 100644 --- a/src/main/java/org/scijava/ui/viewer/DisplayWindow.java +++ b/src/main/java/org/scijava/ui/viewer/DisplayWindow.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c9d9cea64..b53271ee6 100644 --- a/src/main/java/org/scijava/ui/viewer/text/AbstractTextDisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/text/AbstractTextDisplayViewer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 26702b2bb..cd53bdc2d 100644 --- a/src/main/java/org/scijava/ui/viewer/text/TextDisplayPanel.java +++ b/src/main/java/org/scijava/ui/viewer/text/TextDisplayPanel.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2a8c44b51..8799c7ec7 100644 --- a/src/main/java/org/scijava/ui/viewer/text/TextDisplayViewer.java +++ b/src/main/java/org/scijava/ui/viewer/text/TextDisplayViewer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0c91b9454..def8f4eb9 100644 --- a/src/main/java/org/scijava/util/AbstractPrimitiveArray.java +++ b/src/main/java/org/scijava/util/AbstractPrimitiveArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f4836730d..b65cce633 100644 --- a/src/main/java/org/scijava/util/AppUtils.java +++ b/src/main/java/org/scijava/util/AppUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -133,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); @@ -174,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 52d1c3378..f2059c2c7 100644 --- a/src/main/java/org/scijava/util/ArrayUtils.java +++ b/src/main/java/org/scijava/util/ArrayUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -91,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 8a02aed89..32ff8e8b4 100644 --- a/src/main/java/org/scijava/util/BoolArray.java +++ b/src/main/java/org/scijava/util/BoolArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 69617306a..4d7a72d28 100644 --- a/src/main/java/org/scijava/util/ByteArray.java +++ b/src/main/java/org/scijava/util/ByteArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 edfeff177..45f8c70af 100644 --- a/src/main/java/org/scijava/util/Bytes.java +++ b/src/main/java/org/scijava/util/Bytes.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3c2914f25..099db97ec 100644 --- a/src/main/java/org/scijava/util/CharArray.java +++ b/src/main/java/org/scijava/util/CharArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f394a860e..fa9be7491 100644 --- a/src/main/java/org/scijava/util/CheckSezpoz.java +++ b/src/main/java/org/scijava/util/CheckSezpoz.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ea0d8fef7..09961183e 100644 --- a/src/main/java/org/scijava/util/ClassUtils.java +++ b/src/main/java/org/scijava/util/ClassUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -193,7 +190,7 @@ public static void getAnnotatedFields( cachedFields = fieldCache.getList(c, annotationClass); } - fields.addAll(cachedFields); + if (cachedFields != null) fields.addAll(cachedFields); } /** @@ -352,6 +349,7 @@ public static void setValue(final Field field, final Object instance, // -- Comparison -- + // START HERE: Migrate remaining methods to Types, then deprecate this class. /** * Compares two {@link Class} objects using their fully qualified names. *

    @@ -698,12 +696,8 @@ private static class CacheMap extends public List getList(final Class c, final Class annotationClass) { - List annotatedFields = null; final Map, List> annotationTypes = get(c); - if (annotationTypes != null) { - annotatedFields = annotationTypes.get(annotationClass); - } - return annotatedFields; + return annotationTypes == null ? null : annotationTypes.get(annotationClass); } /** diff --git a/src/main/java/org/scijava/util/ColorRGB.java b/src/main/java/org/scijava/util/ColorRGB.java index 3151f7f62..305fbbbe0 100644 --- a/src/main/java/org/scijava/util/ColorRGB.java +++ b/src/main/java/org/scijava/util/ColorRGB.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 7b9b1d038..4bab90ddc 100644 --- a/src/main/java/org/scijava/util/ColorRGBA.java +++ b/src/main/java/org/scijava/util/ColorRGBA.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f9f3fe292..60fa3dc8c 100644 --- a/src/main/java/org/scijava/util/Colors.java +++ b/src/main/java/org/scijava/util/Colors.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4e2a95057..11ed3f879 100644 --- a/src/main/java/org/scijava/util/CombineAnnotations.java +++ b/src/main/java/org/scijava/util/CombineAnnotations.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 062182c15..ce758eed0 100644 --- a/src/main/java/org/scijava/util/Combiner.java +++ b/src/main/java/org/scijava/util/Combiner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e2e5428da..b902d2335 100644 --- a/src/main/java/org/scijava/util/ConversionUtils.java +++ b/src/main/java/org/scijava/util/ConversionUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,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 @@ -56,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 -- @@ -212,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 0c7c6a268..e7ce7cb53 100644 --- a/src/main/java/org/scijava/util/DebugUtils.java +++ b/src/main/java/org/scijava/util/DebugUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,7 +36,6 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Map; /** @@ -67,6 +63,32 @@ public static String getStackTrace(final Throwable t) { } } + /** + * Provides a stack dump of the given thread. + *

    + * The output is similar to a subset of that given when Ctrl+\ (or Ctrl+Pause + * on Windows) is pressed from the console. + *

    + */ + public static String getStackDump(final Thread thread) { + return getStackDump(thread, thread.getStackTrace()); + } + + /** + * Provides a stack dump of the given thread + call stack. + *

    + * The output is similar to a subset of that given when Ctrl+\ (or Ctrl+Pause + * on Windows) is pressed from the console. + *

    + */ + public static String getStackDump(final Thread thread, + final StackTraceElement[] stackTrace) + { + final StringBuilder sb = new StringBuilder(); + dumpThread(thread, stackTrace, sb); + return sb.toString(); + } + /** * Provides a complete stack dump of all threads. *

    @@ -82,13 +104,7 @@ public static String getStackDump() { // sort list of threads by name final ArrayList threads = new ArrayList<>(stackTraces.keySet()); - Collections.sort(threads, new Comparator() { - - @Override - public int compare(final Thread t1, final Thread t2) { - return t1.getName().compareTo(t2.getName()); - } - }); + Collections.sort(threads, (t1, t2) -> t1.getName().compareTo(t2.getName())); for (final Thread t : threads) { dumpThread(t, stackTraces.get(t), sb); diff --git a/src/main/java/org/scijava/util/DefaultTreeNode.java b/src/main/java/org/scijava/util/DefaultTreeNode.java index c4f722ab3..8c9290a78 100644 --- a/src/main/java/org/scijava/util/DefaultTreeNode.java +++ b/src/main/java/org/scijava/util/DefaultTreeNode.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 725a7628d..172f54a9a 100644 --- a/src/main/java/org/scijava/util/DigestUtils.java +++ b/src/main/java/org/scijava/util/DigestUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,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. @@ -101,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 2108fb609..a75b9b266 100644 --- a/src/main/java/org/scijava/util/DoubleArray.java +++ b/src/main/java/org/scijava/util/DoubleArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 bd42f055b..a233d7fd5 100644 --- a/src/main/java/org/scijava/util/FileUtils.java +++ b/src/main/java/org/scijava/util/FileUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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; @@ -58,6 +55,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.scijava.Context; + /** * Useful methods for working with file paths. * @@ -664,7 +663,7 @@ public static Map findResources(final String regex, final String pathPrefix, final File baseDirectory) { // scan URL resource paths first - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final ClassLoader loader = Context.getClassLoader(); final ArrayList urls = new ArrayList<>(); try { urls.addAll(Collections.list(loader.getResources(pathPrefix + "/"))); @@ -729,9 +728,10 @@ private static String classifiers() { "shaded", "sources", "javadoc", - "native", - "(natives-)?(android|linux|macosx|solaris|windows)-" + - "(aarch64|amd64|arm|armv6|armv6hf|i586|universal|x86|x86_64)", + "natives?-?\\w*", + "(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 26464d35e..1911dcd7a 100644 --- a/src/main/java/org/scijava/util/FloatArray.java +++ b/src/main/java/org/scijava/util/FloatArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 75b52c44f..f73fc78f6 100644 --- a/src/main/java/org/scijava/util/GenericUtils.java +++ b/src/main/java/org/scijava/util/GenericUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3c6014ded..4916ca205 100644 --- a/src/main/java/org/scijava/util/IntArray.java +++ b/src/main/java/org/scijava/util/IntArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 0501616a3..8110aa996 100644 --- a/src/main/java/org/scijava/util/IntCoords.java +++ b/src/main/java/org/scijava/util/IntCoords.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a96c98e39..be12b1035 100644 --- a/src/main/java/org/scijava/util/IntRect.java +++ b/src/main/java/org/scijava/util/IntRect.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 56a4319dd..5a28e023d 100644 --- a/src/main/java/org/scijava/util/IteratorPlus.java +++ b/src/main/java/org/scijava/util/IteratorPlus.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 731bd74a0..83afb110f 100644 --- a/src/main/java/org/scijava/util/LastRecentlyUsed.java +++ b/src/main/java/org/scijava/util/LastRecentlyUsed.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -146,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 1ef4e99e4..2f4ad2d19 100644 --- a/src/main/java/org/scijava/util/LineOutputStream.java +++ b/src/main/java/org/scijava/util/LineOutputStream.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1c169f351..e423fa616 100644 --- a/src/main/java/org/scijava/util/ListUtils.java +++ b/src/main/java/org/scijava/util/ListUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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 c0ac04d1f..351580338 100644 --- a/src/main/java/org/scijava/util/LongArray.java +++ b/src/main/java/org/scijava/util/LongArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 aad982446..6e4cd5dd3 100644 --- a/src/main/java/org/scijava/util/Manifest.java +++ b/src/main/java/org/scijava/util/Manifest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a3a8707b3..9bad0ab73 100644 --- a/src/main/java/org/scijava/util/MersenneTwisterFast.java +++ b/src/main/java/org/scijava/util/MersenneTwisterFast.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6f274e50e..63582c0cc 100644 --- a/src/main/java/org/scijava/util/MetaInfCombiner.java +++ b/src/main/java/org/scijava/util/MetaInfCombiner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 e59621e4e..ec807ab8e 100644 --- a/src/main/java/org/scijava/util/MirrorWebsite.java +++ b/src/main/java/org/scijava/util/MirrorWebsite.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -61,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 428b4e819..4476e9a4b 100644 --- a/src/main/java/org/scijava/util/MiscUtils.java +++ b/src/main/java/org/scijava/util/MiscUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d7b51272f..11a228345 100644 --- a/src/main/java/org/scijava/util/NumberUtils.java +++ b/src/main/java/org/scijava/util/NumberUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -81,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; } @@ -91,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 f1af6eb58..aa12acc08 100644 --- a/src/main/java/org/scijava/util/ObjectArray.java +++ b/src/main/java/org/scijava/util/ObjectArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,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 a6420398f..54c0434ab 100644 --- a/src/main/java/org/scijava/util/POM.java +++ b/src/main/java/org/scijava/util/POM.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,6 +40,7 @@ import javax.xml.parsers.ParserConfigurationException; +import org.scijava.Context; import org.scijava.Versioned; import org.xml.sax.SAXException; @@ -184,18 +182,19 @@ public String getCIManagementURL() { // -- Comparable methods -- - @Override - public int compareTo(final POM pom) { + private static final Comparator STRING_COMPARATOR = // + Comparator.nullsFirst(String::compareTo); + private static final Comparator POM_COMPARATOR = Comparator// // sort by groupId first - final int gid = getGroupId().compareTo(pom.getGroupId()); - if (gid != 0) return gid; - + .comparing(POM::getGroupId, STRING_COMPARATOR) // sort by artifactId second - final int aid = getArtifactId().compareTo(pom.getArtifactId()); - if (aid != 0) return aid; - + .thenComparing(POM::getArtifactId, STRING_COMPARATOR)// // finally, sort by version - return compareVersions(getVersion(), pom.getVersion()); + .thenComparing(POM::getVersion, POM::compareVersions); + + @Override + public int compareTo(final POM pom) { + return POM_COMPARATOR.compare(this, pom); } // -- Versioned methods -- @@ -216,12 +215,25 @@ public String getVersion() { // -- Utility methods -- + /** + * Gets the Maven POM associated with the given class. + * + * @param c The class to use as a base when searching for a pom.xml. + * @return {@link POM} object representing the discovered POM, or null if no + * POM could be found. + */ + public static POM getPOM(final Class c) { + return getPOM(c, null, null); + } + /** * Gets the Maven POM associated with the given class. * * @param c The class to use as a base when searching for a pom.xml. * @param groupId The Maven groupId of the desired POM. * @param artifactId The Maven artifactId of the desired POM. + * @return {@link POM} object representing the discovered POM, or null if no + * POM could be found. */ public static POM getPOM(final Class c, final String groupId, final String artifactId) @@ -232,11 +244,24 @@ public static POM getPOM(final Class c, final String groupId, location.toString().endsWith(".jar")) { // look for pom.xml in JAR's META-INF/maven subdirectory - final String pomPath = - "META-INF/maven/" + groupId + "/" + artifactId + "/pom.xml"; - final URL pomURL = - new URL("jar:" + location.toString() + "!/" + pomPath); - return new POM(pomURL); + if (groupId == null || artifactId == null) { + // groupId and/or artifactId is unknown; scan for the POM + final URL pomBase = new URL("jar:" + // + location.toString() + "!/META-INF/maven"); + for (final URL url : FileUtils.listContents(pomBase, true, true)) { + if (url.toExternalForm().endsWith("/pom.xml")) { + return new POM(url); + } + } + } + else { + // known groupId and artifactId; grab it directly + final String pomPath = + "META-INF/maven/" + groupId + "/" + artifactId + "/pom.xml"; + final URL pomURL = + new URL("jar:" + location.toString() + "!/" + pomPath); + return new POM(pomURL); + } } // look for the POM in the class's base directory final File file = FileUtils.urlToFile(location); @@ -244,13 +269,7 @@ public static POM getPOM(final Class c, final String groupId, final File pomFile = new File(baseDir, "pom.xml"); return new POM(pomFile); } - catch (final IOException e) { - return null; - } - catch (final ParserConfigurationException e) { - return null; - } - catch (final SAXException e) { + catch (final IOException | ParserConfigurationException | SAXException e) { return null; } } @@ -259,8 +278,7 @@ public static POM getPOM(final Class c, final String groupId, public static List getAllPOMs() { // find all META-INF/maven/ folders on the classpath final String pomPrefix = "META-INF/maven/"; - final ClassLoader classLoader = - Thread.currentThread().getContextClassLoader(); + final ClassLoader classLoader = Context.getClassLoader(); final Enumeration resources; try { resources = classLoader.getResources(pomPrefix); @@ -317,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 acd9459ba..215759cac 100644 --- a/src/main/java/org/scijava/util/PlatformUtils.java +++ b/src/main/java/org/scijava/util/PlatformUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f9d13609f..72f63bac7 100644 --- a/src/main/java/org/scijava/util/Prefs.java +++ b/src/main/java/org/scijava/util/Prefs.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 192498e89..51ac3f30a 100644 --- a/src/main/java/org/scijava/util/PrimitiveArray.java +++ b/src/main/java/org/scijava/util/PrimitiveArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8dee1e5c8..3b23b3c1c 100644 --- a/src/main/java/org/scijava/util/ProcessUtils.java +++ b/src/main/java/org/scijava/util/ProcessUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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..bfbac09e2 --- /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 - 2025 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 d0cba28ba..008b84efa 100644 --- a/src/main/java/org/scijava/util/Query.java +++ b/src/main/java/org/scijava/util/Query.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 297465013..559b87304 100644 --- a/src/main/java/org/scijava/util/ReadInto.java +++ b/src/main/java/org/scijava/util/ReadInto.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 32bf04be0..97e61e00c 100644 --- a/src/main/java/org/scijava/util/RealCoords.java +++ b/src/main/java/org/scijava/util/RealCoords.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 bb5c9e6f4..4f355cd73 100644 --- a/src/main/java/org/scijava/util/RealRect.java +++ b/src/main/java/org/scijava/util/RealRect.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 241f50373..3402b78f9 100644 --- a/src/main/java/org/scijava/util/ReflectException.java +++ b/src/main/java/org/scijava/util/ReflectException.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2a2fe9554..fd7aa908a 100644 --- a/src/main/java/org/scijava/util/ReflectedUniverse.java +++ b/src/main/java/org/scijava/util/ReflectedUniverse.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5efa456d6..ea9bd034c 100644 --- a/src/main/java/org/scijava/util/ServiceCombiner.java +++ b/src/main/java/org/scijava/util/ServiceCombiner.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,10 +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 @@ -61,8 +58,7 @@ public void combine(final File outputDirectory) throws IOException { final Map files = new HashMap<>(); final Enumeration directories = - Thread.currentThread().getContextClassLoader().getResources( - SERVICES_PREFIX); + Context.getClassLoader().getResources(SERVICES_PREFIX); // Iterate over all the service files while (directories.hasMoreElements()) { diff --git a/src/main/java/org/scijava/util/ShortArray.java b/src/main/java/org/scijava/util/ShortArray.java index 444ed8e21..354d31031 100644 --- a/src/main/java/org/scijava/util/ShortArray.java +++ b/src/main/java/org/scijava/util/ShortArray.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 863a08c06..a1a8d82eb 100644 --- a/src/main/java/org/scijava/util/Sizable.java +++ b/src/main/java/org/scijava/util/Sizable.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 925b90ce1..11eb6bdc0 100644 --- a/src/main/java/org/scijava/util/SizableArrayList.java +++ b/src/main/java/org/scijava/util/SizableArrayList.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 6b6a389ae..809b1a5c9 100644 --- a/src/main/java/org/scijava/util/StringMaker.java +++ b/src/main/java/org/scijava/util/StringMaker.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 c2155e277..90b2e9756 100644 --- a/src/main/java/org/scijava/util/StringUtils.java +++ b/src/main/java/org/scijava/util/StringUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3b6eaa1e9..8a4dcfe39 100644 --- a/src/main/java/org/scijava/util/Timing.java +++ b/src/main/java/org/scijava/util/Timing.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 5f2063349..20af64acc 100644 --- a/src/main/java/org/scijava/util/TreeNode.java +++ b/src/main/java/org/scijava/util/TreeNode.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 4a4d54db2..a36fa353d 100644 --- a/src/main/java/org/scijava/util/TunePlayer.java +++ b/src/main/java/org/scijava/util/TunePlayer.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f0c1683b6..a75ef8311 100644 --- a/src/main/java/org/scijava/util/Types.java +++ b/src/main/java/org/scijava/util/Types.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2016 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 @@ -29,10 +27,6 @@ * #L% */ -package org.scijava.util; - -import java.io.File; - // Portions of this class were adapted from the // org.apache.commons.lang3.reflect.TypeUtils and // org.apache.commons.lang3.Validate classes of @@ -46,6 +40,9 @@ // // See NOTICE.txt for further details on third-party licenses. +package org.scijava.util; + +import java.io.File; import java.io.Serializable; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -70,7 +67,7 @@ import java.util.Objects; import java.util.Set; -import org.scijava.util.FileUtils; +import org.scijava.Context; /** * Utility class for working with generic types, fields and methods. @@ -84,8 +81,27 @@ *
  • GenTyRef (Generic Type * Reflector), a library for runtime generic type introspection.
  • * + *

    + * All three of these libraries contain fantastic generics-related logic, but + * none of the three contained everything that SciJava needed for all its use + * cases. Hence, we have drawn from sources as needed to create a unified + * generics API for use from SciJava applications. See in particular the + * SciJava Ops project, + * which utilizes these functions heavily. + *

    + *

    + * NB: The + * org.apache.commons.reflect.TypeUtils class of + * Apache Commons + * Lang version 3.4 is forked internally within this class. We did this for + * two reasons: 1) to avoid bringing in the whole of Apache Commons Lang as a + * dependency; and 2) to fix an infinite recursion bug in the + * {@code TypeUtils.toString(Type)} method. + *

    * * @author Curtis Rueden + * @author Gabe Selzer */ public final class Types { @@ -205,8 +221,8 @@ public static Class load(final String name, final ClassLoader classLoader, // load the class! try { - final ClassLoader cl = classLoader == null ? // - Thread.currentThread().getContextClassLoader() : classLoader; + final ClassLoader cl = // + classLoader != null ? classLoader : Context.getClassLoader(); return cl.loadClass(className); } catch (final Throwable t) { @@ -349,6 +365,8 @@ public static String name(final Type t) { public static Class raw(final Type type) { if (type == null) return null; if (type instanceof Class) return (Class) type; + if (type instanceof GenericArrayType) + return array(raw(((GenericArrayType) type).getGenericComponentType())); final List> c = raws(type); if (c == null || c.size() == 0) return null; return c.get(0); @@ -762,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. @@ -780,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. @@ -791,22 +865,22 @@ public static T enumValue(final String name, final Class dest) { public static ParameterizedType parameterize(final Class rawType, final Type... typeArgs) { - return parameterize(rawType, rawType.getDeclaringClass(), typeArgs); + return parameterizeWithOwner(null, rawType, typeArgs); } /** * Creates a new {@link ParameterizedType} of the given class together with * the specified type arguments. * - * @param rawType The class of the {@link ParameterizedType}. * @param ownerType The owner type of the parameterized class. + * @param rawType The class of the {@link ParameterizedType}. * @param typeArgs The type arguments to use in parameterizing it. * @return The newly created {@link ParameterizedType}. */ - public static ParameterizedType parameterize(final Class rawType, - final Type ownerType, final Type... typeArgs) + public static ParameterizedType parameterizeWithOwner(final Type ownerType, + final Class rawType, final Type... typeArgs) { - return new TypeUtils.ParameterizedTypeImpl(rawType, ownerType, typeArgs); + return TypeUtils.parameterizeWithOwner(ownerType, rawType, typeArgs); } /** @@ -980,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, @@ -1416,7 +1490,7 @@ private static boolean isAssignable(final Type type, // parameters must either be absent from the subject type, within // the bounds of the wildcard type, or be an exact match to the // parameters of the target type. - if (fromTypeArg != null && !toTypeArg.equals(fromTypeArg) && + if (fromTypeArg != null && !fromTypeArg.equals(toTypeArg) && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg, typeVarAssigns))) { @@ -3206,7 +3280,7 @@ else if (isMissingTypeParameters(clazz)) { Arrays.fill(arguments, UNBOUND_WILDCARD); final Type owner = clazz.getDeclaringClass() == null ? null : addWildcardParameters(clazz.getDeclaringClass()); - return parameterize(clazz, owner, arguments); + return parameterizeWithOwner(owner, clazz, arguments); } else { return clazz; @@ -3467,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; @@ -3584,9 +3656,9 @@ public static Type capture(final Type type) { for (final CaptureTypeImpl captured : toInit) { captured.init(varMap); } - final Type ownerType = (pType.getOwnerType() == null) ? null : capture( + final Type ownerType = pType.getOwnerType() == null ? null : capture( pType.getOwnerType()); - return parameterize(clazz, ownerType, capturedArguments); + return parameterizeWithOwner(ownerType, clazz, capturedArguments); } return type; } @@ -3764,9 +3836,10 @@ else if (type instanceof TypeVariable) { } else if (type instanceof ParameterizedType) { final ParameterizedType pType = (ParameterizedType) type; - return parameterize((Class) pType.getRawType(), pType - .getOwnerType() == null ? pType.getOwnerType() : map(pType - .getOwnerType()), map(pType.getActualTypeArguments())); + final Type ownerType = pType.getOwnerType() == null ? // + pType.getOwnerType() : map(pType.getOwnerType()); + return parameterizeWithOwner(ownerType, (Class) pType.getRawType(), + map(pType.getActualTypeArguments())); } else if (type instanceof WildcardType) { final WildcardType wType = (WildcardType) type; diff --git a/src/main/java/org/scijava/util/UnitUtils.java b/src/main/java/org/scijava/util/UnitUtils.java index 9fa762fc7..445f16046 100644 --- a/src/main/java/org/scijava/util/UnitUtils.java +++ b/src/main/java/org/scijava/util/UnitUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 8e0e74b5c..ea012b9a1 100644 --- a/src/main/java/org/scijava/util/VersionUtils.java +++ b/src/main/java/org/scijava/util/VersionUtils.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -146,15 +143,25 @@ private static String[] splitDots(final String s) { /** Compares one token of a multi-token version string. */ private static int compareToken(final String t1, final String t2) { final int i1 = digitIndex(t1), i2 = digitIndex(t2); + String suffix1 = t1, suffix2 = t2; if (i1 > 0 && i2 > 0) { // Versions start with digits; compare them numerically. final long d1 = Long.parseLong(t1.substring(0, i1)); final long d2 = Long.parseLong(t2.substring(0, i2)); if (d1 < d2) return -1; if (d1 > d2) return 1; + suffix1 = t1.substring(i1); + suffix2 = t2.substring(i2); } - // Compare remaining characters lexicographically. - return t1.substring(i1).compareTo(t2.substring(i2)); + + // Final version (empty string) is larger than non-final (non-empty). + // For example: 2.0.0 > 2.0.0-beta-1. + if (suffix1.isEmpty() && suffix2.isEmpty()) return 0; + if (suffix1.isEmpty()) return 1; + if (suffix2.isEmpty()) return -1; + + // Compare lexicographically. + return suffix1.compareTo(suffix2); } /** Gets the subsequent index to all the given string's leading digits. */ diff --git a/src/main/java/org/scijava/util/XML.java b/src/main/java/org/scijava/util/XML.java index ab904e876..5a3f0a049 100644 --- a/src/main/java/org/scijava/util/XML.java +++ b/src/main/java/org/scijava/util/XML.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 72731ae3b..b9af9fd48 100644 --- a/src/main/java/org/scijava/welcome/DefaultWelcomeService.java +++ b/src/main/java/org/scijava/welcome/DefaultWelcomeService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 d3e97197f..ac690f3bc 100644 --- a/src/main/java/org/scijava/welcome/WelcomeService.java +++ b/src/main/java/org/scijava/welcome/WelcomeService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 9d3f656fe..2f38dc848 100644 --- a/src/main/java/org/scijava/welcome/event/WelcomeEvent.java +++ b/src/main/java/org/scijava/welcome/event/WelcomeEvent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 fefc9bb47..5b9e59ec5 100644 --- a/src/main/java/org/scijava/widget/AbstractInputHarvester.java +++ b/src/main/java/org/scijava/widget/AbstractInputHarvester.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,7 +30,11 @@ package org.scijava.widget; import java.util.ArrayList; +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; @@ -120,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 @@ -129,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") - List compatibleInputs = - new ArrayList(convertService.getCompatibleInputs(type)); - compatibleInputs.addAll(objectService.getObjects(type)); - return 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 24006c63e..5b6637b19 100644 --- a/src/main/java/org/scijava/widget/AbstractInputPanel.java +++ b/src/main/java/org/scijava/widget/AbstractInputPanel.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2557f9714..bedf6d594 100644 --- a/src/main/java/org/scijava/widget/AbstractInputWidget.java +++ b/src/main/java/org/scijava/widget/AbstractInputWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 99d62816e..0768762a2 100644 --- a/src/main/java/org/scijava/widget/Button.java +++ b/src/main/java/org/scijava/widget/Button.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 56129404e..a56b33065 100644 --- a/src/main/java/org/scijava/widget/ButtonWidget.java +++ b/src/main/java/org/scijava/widget/ButtonWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b956c764f..25ff52afe 100644 --- a/src/main/java/org/scijava/widget/ChoiceWidget.java +++ b/src/main/java/org/scijava/widget/ChoiceWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 22b1f6d6d..427f64922 100644 --- a/src/main/java/org/scijava/widget/ColorWidget.java +++ b/src/main/java/org/scijava/widget/ColorWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 fc60b932d..4cc60c0b5 100644 --- a/src/main/java/org/scijava/widget/DateWidget.java +++ b/src/main/java/org/scijava/widget/DateWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b11012be1..7bea4bc8c 100644 --- a/src/main/java/org/scijava/widget/DefaultWidgetModel.java +++ b/src/main/java/org/scijava/widget/DefaultWidgetModel.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,7 +29,6 @@ package org.scijava.widget; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; @@ -47,6 +43,7 @@ import org.scijava.module.Module; import org.scijava.module.ModuleItem; import org.scijava.module.ModuleService; +import org.scijava.object.ObjectService; import org.scijava.plugin.Parameter; import org.scijava.thread.ThreadService; import org.scijava.util.NumberUtils; @@ -74,6 +71,9 @@ public class DefaultWidgetModel extends AbstractContextual implements WidgetMode @Parameter private ModuleService moduleService; + @Parameter + private ObjectService objectService; + @Parameter(required = false) private LogService log; @@ -128,12 +128,7 @@ public String getWidgetLabel() { @Override public boolean isStyle(final String style) { - final String widgetStyle = getItem().getWidgetStyle(); - if (widgetStyle == null) return style == null; - for (final String s : widgetStyle.split(",")) { - if (s.equals(style)) return true; - } - return false; + return WidgetStyle.isStyle(getItem(), style); } @Override @@ -160,6 +155,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) { @@ -169,14 +165,10 @@ public void setValue(final Object value) { module.setInput(name, convertedInput); if (initialized) { - threadService.run(new Runnable() { - - @Override - public void run() { - callback(); - inputPanel.refresh(); // must be on AWT thread? - module.preview(); - } + threadService.queue(() -> { + callback(); + inputPanel.refresh(); // must be on AWT thread? + module.preview(); }); } } @@ -228,10 +220,11 @@ 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++) { - choices[i] = choicesList.get(i).toString(); + choices[i] = objectService.getName(choicesList.get(i)); } return choices; } @@ -296,11 +289,10 @@ public boolean isInitialized() { /** * 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 f80fc641b..6f35b2efa 100644 --- a/src/main/java/org/scijava/widget/DefaultWidgetService.java +++ b/src/main/java/org/scijava/widget/DefaultWidgetService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 b7f2203a5..fc310519b 100644 --- a/src/main/java/org/scijava/widget/FileListWidget.java +++ b/src/main/java/org/scijava/widget/FileListWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 f31c2ac28..5567cb967 100644 --- a/src/main/java/org/scijava/widget/FileWidget.java +++ b/src/main/java/org/scijava/widget/FileWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -62,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 6d4933790..fe27f5480 100644 --- a/src/main/java/org/scijava/widget/InputHarvester.java +++ b/src/main/java/org/scijava/widget/InputHarvester.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 1087924f7..f937027bc 100644 --- a/src/main/java/org/scijava/widget/InputPanel.java +++ b/src/main/java/org/scijava/widget/InputPanel.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 3f3b2ad43..221c3770b 100644 --- a/src/main/java/org/scijava/widget/InputWidget.java +++ b/src/main/java/org/scijava/widget/InputWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 9d8bc2234..20347c3b2 100644 --- a/src/main/java/org/scijava/widget/MessageWidget.java +++ b/src/main/java/org/scijava/widget/MessageWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a48567eac..79bfa46cd 100644 --- a/src/main/java/org/scijava/widget/NumberWidget.java +++ b/src/main/java/org/scijava/widget/NumberWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 fd7ce5ce2..27c9560c6 100644 --- a/src/main/java/org/scijava/widget/ObjectWidget.java +++ b/src/main/java/org/scijava/widget/ObjectWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 a89b49446..716750d69 100644 --- a/src/main/java/org/scijava/widget/TextWidget.java +++ b/src/main/java/org/scijava/widget/TextWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 04c00a6f9..8a56a9662 100644 --- a/src/main/java/org/scijava/widget/ToggleWidget.java +++ b/src/main/java/org/scijava/widget/ToggleWidget.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 ab06587a9..2b7f56e0a 100644 --- a/src/main/java/org/scijava/widget/UIComponent.java +++ b/src/main/java/org/scijava/widget/UIComponent.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 2bb202e46..a2ee20dcd 100644 --- a/src/main/java/org/scijava/widget/WidgetModel.java +++ b/src/main/java/org/scijava/widget/WidgetModel.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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/WidgetService.java b/src/main/java/org/scijava/widget/WidgetService.java index 85c73afbe..01857a29c 100644 --- a/src/main/java/org/scijava/widget/WidgetService.java +++ b/src/main/java/org/scijava/widget/WidgetService.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source 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 new file mode 100644 index 000000000..65491717d --- /dev/null +++ b/src/main/java/org/scijava/widget/WidgetStyle.java @@ -0,0 +1,115 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.widget; + +import org.scijava.module.ModuleItem; + +public class WidgetStyle { + private WidgetStyle() { + // prevent instantiation of utility class + } + + /** + * Check whether a given widget style contains the target style. + * + * @param widgetStyle + * The style declaration to test, usually a comma-separated + * {@code String}; trailing spaces are ignored. + * @param target + * The style being checked, case-insensitive. + * @return {@code true} if the target style matches. + */ + public static boolean isStyle(String widgetStyle, String target) { + if (widgetStyle == null || target == null) + return widgetStyle == target; + for (final String s : widgetStyle.split(",")) { + if (s.trim().toLowerCase().equals(target.toLowerCase())) return true; + } + return false; + } + + /** + * Check whether a given {@link ModuleItem} has the target style. + * + * @param item + * The module item to test. + * @param target + * The style being checked, case-insensitive. + * @return {@code true} if the module item has the target style. + */ + public static boolean isStyle(ModuleItem item, String target) { + return isStyle(item.getWidgetStyle(), target); + } + + /** + * Get the modifying value for a given style attribute in a style declaration. + * + *

    + * For example, for {@code style="format:#0.00"}, this will return + * {@code "#0.00"}. + *

    + * + * @param widgetStyle + * The style declaration string, e.g. "format:#0.00". + * @param target + * The target style attribute, e.g. "format". + * @return The modifier for the given target, e.g. "#0.00". + */ + public static String getStyleModifier(String widgetStyle, String target) { + if (widgetStyle == null || target == null) + return null; + String[] styles = widgetStyle.split(","); + for (String s : styles) { + if (s.trim().toLowerCase().startsWith(target.toLowerCase())) { + return s.split(":")[1]; + } + } + return null; + } + + /** + * Get an array of all modifying values for a given style attribute. + * + *

    + * For example, for {@code style="extensions:png/gif/bmp"}, this will return {@code ["png", "gif", "bmp"]}. + *

    + * + * @param widgetStyle + * The style declaration string, e.g. "extensions:png/gif/bmp". + * @param target + * The target style attribute, e.g. "extensions". + * @return An array of modifiers for the given target, e.g. ["png", "gif", "bmp"]. + */ + public static String[] getStyleModifiers(String widgetStyle, String target) { + String suffix = getStyleModifier(widgetStyle, target); + if (suffix == null) return null; + return suffix.split("/"); + } + +} diff --git a/src/test/java/org/scijava/ContextCreationTest.java b/src/test/java/org/scijava/ContextCreationTest.java index 9c6e15c82..9b5769ef3 100644 --- a/src/test/java/org/scijava/ContextCreationTest.java +++ b/src/test/java/org/scijava/ContextCreationTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -45,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; @@ -87,7 +86,6 @@ public void testNoPlugins() { public void testFull() { final Class[] expected = { org.scijava.event.DefaultEventService.class, - org.scijava.script.DefaultScriptService.class, org.scijava.app.DefaultAppService.class, org.scijava.app.DefaultStatusService.class, org.scijava.command.DefaultCommandService.class, @@ -113,10 +111,12 @@ public void testFull() { org.scijava.prefs.DefaultPrefService.class, org.scijava.run.DefaultRunService.class, org.scijava.script.DefaultScriptHeaderService.class, + org.scijava.script.DefaultScriptService.class, org.scijava.script.process.DefaultScriptProcessorService.class, org.scijava.startup.DefaultStartupService.class, org.scijava.task.DefaultTaskService.class, org.scijava.text.DefaultTextService.class, + org.scijava.text.io.DefaultTextIOService.class, org.scijava.thread.DefaultThreadService.class, org.scijava.tool.DefaultToolService.class, org.scijava.ui.DefaultUIService.class, @@ -151,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. @@ -443,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..4f66ab6f9 --- /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 - 2025 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 53aa7ab40..df3c46ece 100644 --- a/src/test/java/org/scijava/ContextInjectionTest.java +++ b/src/test/java/org/scijava/ContextInjectionTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 new file mode 100644 index 000000000..9daf637c6 --- /dev/null +++ b/src/test/java/org/scijava/SciJavaTest.java @@ -0,0 +1,65 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; + +import org.junit.Test; +import org.scijava.plugin.PluginInfo; + +/** + * Tests {@link SciJava}. + * + * @author Curtis Rueden + */ +public class SciJavaTest { + + @Test + public void testInfo() { + final SciJava sj = new SciJava(); + + final PluginInfo infoFromObject = sj.getInfo(); + final PluginInfo infoFromServiceNoType = // + sj.plugin().getPlugin(SciJava.class); + final PluginInfo infoFromServiceWithType = // + sj.plugin().getPlugin(SciJava.class, Gateway.class); + assertSame(infoFromServiceNoType, infoFromObject); + assertSame(infoFromServiceWithType, infoFromObject); + + assertNotNull(infoFromObject); + assertSame(Gateway.class, infoFromObject.getPluginType()); + + assertEquals(Priority.NORMAL, sj.getPriority(), 0); + + sj.dispose(); + } +} diff --git a/src/test/java/org/scijava/annotations/AnnotatedA.java b/src/test/java/org/scijava/annotations/AnnotatedA.java index 27c4f1db9..4c9977496 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedA.java +++ b/src/test/java/org/scijava/annotations/AnnotatedA.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 a8644a6c9..46ccb442c 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedB.java +++ b/src/test/java/org/scijava/annotations/AnnotatedB.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 b4d0bb2de..777b949f4 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedC.java +++ b/src/test/java/org/scijava/annotations/AnnotatedC.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 ac122ff03..d898df6d7 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedD.java +++ b/src/test/java/org/scijava/annotations/AnnotatedD.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 f5133e5be..96ed33157 100644 --- a/src/test/java/org/scijava/annotations/AnnotatedInnerClass.java +++ b/src/test/java/org/scijava/annotations/AnnotatedInnerClass.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 b7881c1b3..f7cb7e0ec 100644 --- a/src/test/java/org/scijava/annotations/Complex.java +++ b/src/test/java/org/scijava/annotations/Complex.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 249511a57..8a6d243e4 100644 --- a/src/test/java/org/scijava/annotations/DirectoryIndexerTest.java +++ b/src/test/java/org/scijava/annotations/DirectoryIndexerTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 d2f663f35..6bd63ace5 100644 --- a/src/test/java/org/scijava/annotations/EclipseHelperTest.java +++ b/src/test/java/org/scijava/annotations/EclipseHelperTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 75efc3e7a..9ffb333cd 100644 --- a/src/test/java/org/scijava/annotations/Fruit.java +++ b/src/test/java/org/scijava/annotations/Fruit.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 eeb2f5503..6bf5d5d13 100644 --- a/src/test/java/org/scijava/annotations/LegacyTest.java +++ b/src/test/java/org/scijava/annotations/LegacyTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 709593d4b..90b426367 100644 --- a/src/test/java/org/scijava/annotations/Simple.java +++ b/src/test/java/org/scijava/annotations/Simple.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 f5abb4730..1209d4049 100644 --- a/src/test/java/org/scijava/app/StatusServiceTest.java +++ b/src/test/java/org/scijava/app/StatusServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 new file mode 100644 index 000000000..8531a3dfa --- /dev/null +++ b/src/test/java/org/scijava/command/CommandArrayConverterTest.java @@ -0,0 +1,184 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.command; + +import org.junit.Test; +import org.scijava.Context; +import org.scijava.ItemIO; +import org.scijava.Priority; +import org.scijava.convert.AbstractConverter; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; + +import java.util.concurrent.ExecutionException; + +import static org.junit.Assert.*; + +public class CommandArrayConverterTest { + + @Test + public void testArrayCommandRaw() throws InterruptedException, + ExecutionException + { + final Context context = new Context(CommandService.class); + final CommandService commandService = context.service(CommandService.class); + + UserClass[] userObjects = new UserClass[2]; + userObjects[0] = new UserClass("User Object 0", new Object()); + userObjects[1] = new UserClass("User Object 1", new Object()); + + final CommandModule module = // + commandService.run(CommandRawArrayInput.class, true, "userObjects", userObjects ).get(); // + assertEquals("User Object 0;User Object 1;", module.getOutput("result")); + } + + @Test + public void testArrayConvertFromStringCommandRaw() throws InterruptedException, + ExecutionException + { + final Context context = new Context(CommandService.class); + final CommandService commandService = context.service(CommandService.class); + + final CommandModule module = // + commandService.run(CommandRawArrayInput.class, true, "userObjects", "User Object 0,User Object 1" ).get(); // + + assertEquals("User Object 0;User Object 1;", module.getOutput("result")); + } + + @Test + public void testArrayCommandWildcardGenerics() throws InterruptedException, + ExecutionException + { + final Context context = new Context(CommandService.class); + final CommandService commandService = context.service(CommandService.class); + + UserClass[] userObjects = new UserClass[2]; + userObjects[0] = new UserClass("User Object 0", new Object()); + userObjects[1] = new UserClass("User Object 1", new Object()); + + final CommandModule module = // + commandService.run(CommandGenericsWildcardArrayInput.class, true, "userObjects", userObjects ).get(); // + assertEquals("User Object 0;User Object 1;", module.getOutput("result")); + } + + @Test + public void testArrayConvertFromStringCommandWildcardGenerics() throws InterruptedException, + ExecutionException + { + final Context context = new Context(CommandService.class); + final CommandService commandService = context.service(CommandService.class); + + final CommandModule module = // + commandService.run(CommandGenericsWildcardArrayInput.class, true, "userObjects", "User Object 0,User Object 1" ).get(); // + + assertEquals("User Object 0;User Object 1;", module.getOutput("result")); + } + + /** A command which uses a UserClass Raw Array parameter. */ + @Plugin(type = Command.class) + public static class CommandRawArrayInput implements Command { + + @Parameter + private UserClass[] userObjects; + + @Parameter(type = ItemIO.OUTPUT) + private String result = "default"; + + @Override + public void run() { + final StringBuilder sb = new StringBuilder(); + for (UserClass obj : userObjects) { + sb.append(obj.toString()+";"); + } + result = sb.toString(); + } + } + + /** A command which uses a UserClass Array with generics wildcard */ + @Plugin(type = Command.class) + public static class CommandGenericsWildcardArrayInput implements Command { + + @Parameter + private UserClass[] userObjects; + + @Parameter(type = ItemIO.OUTPUT) + private String result = "default"; + + @Override + public void run() { + final StringBuilder sb = new StringBuilder(); + for (UserClass obj : userObjects) { + sb.append(obj.toString()+";"); + } + result = sb.toString(); + } + } + + @Plugin(type = org.scijava.convert.Converter.class, priority = Priority.LOW) + public static class StringToUserClassConverterNoGenerics extends AbstractConverter { + + @Override + public T convert(Object src, Class dest) { + String str = (String) src; + String[] names = str.split(","); + UserClass[] userObjects = new UserClass[names.length]; + for (int index = 0; index < names.length ; index++) { + userObjects[index] = new UserClass(names[index], new Object()); + } + return (T) userObjects; + } + + @Override + public Class getOutputType() { + return UserClass[].class; + } + + @Override + public Class getInputType() { + return String.class; + } + } + + /** + * Simple class to test input arrays in command + */ + public static class UserClass { + + String name; + + public UserClass(String objectName, T generic_object) { + name = objectName; + } + + public String toString() { + return name; + } + } + +} diff --git a/src/test/java/org/scijava/command/CommandInfoTest.java b/src/test/java/org/scijava/command/CommandInfoTest.java index ded76ecd8..6f1cf1128 100644 --- a/src/test/java/org/scijava/command/CommandInfoTest.java +++ b/src/test/java/org/scijava/command/CommandInfoTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,10 +39,12 @@ import java.util.Arrays; import java.util.Iterator; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.scijava.Context; import org.scijava.command.CommandInfoTest.CommandWithEnumParam.Choice; +import org.scijava.log.LogService; import org.scijava.module.ModuleItem; import org.scijava.plugin.Parameter; @@ -56,14 +55,20 @@ */ public class CommandInfoTest { + private Context ctx; private CommandService commandService; @Before public void setUp() { - final Context ctx = new Context(CommandService.class); + ctx = new Context(CommandService.class); commandService = ctx.getService(CommandService.class); } + @After + public void tearDown() { + ctx.dispose(); + } + @Test public void testEnumParam() { final CommandInfo info = commandService.getCommand( @@ -91,6 +96,12 @@ public void testEnumParam() { choice.getChoices()); } + @Test + public void testDuplicateServiceParameters() { + CommandInfo commandInfo = new CommandInfo(ExtendedServiceCommand.class); + assertTrue(commandInfo.isValid()); + } + // -- Helper classes -- /** A command with an enum parameter. */ @@ -115,4 +126,26 @@ public void run() { // NB: No implementation needed. } } + + private static class ServiceCommand implements Command { + + @Parameter + private LogService logService; + + @Override + public void run() { + // do nothing + } + } + + private static class ExtendedServiceCommand extends ServiceCommand { + + @Parameter + private LogService logService; + + @Override + public void run() { + // do nothing + } + } } diff --git a/src/test/java/org/scijava/command/CommandModuleTest.java b/src/test/java/org/scijava/command/CommandModuleTest.java index 834962d1c..9fb32074f 100644 --- a/src/test/java/org/scijava/command/CommandModuleTest.java +++ b/src/test/java/org/scijava/command/CommandModuleTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 95ae9aa22..ef34da9a4 100644 --- a/src/test/java/org/scijava/command/CommandServiceTest.java +++ b/src/test/java/org/scijava/command/CommandServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 new file mode 100644 index 000000000..3cdc8c35b --- /dev/null +++ b/src/test/java/org/scijava/command/InputsTest.java @@ -0,0 +1,179 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.command; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.InstantiableException; +import org.scijava.module.Module; +import org.scijava.module.ModuleItem; +import org.scijava.module.MutableModuleItem; +import org.scijava.module.process.AbstractPreprocessorPlugin; +import org.scijava.module.process.PreprocessorPlugin; +import org.scijava.plugin.PluginInfo; +import org.scijava.plugin.PluginService; +import org.scijava.widget.InputHarvester; +import org.scijava.widget.NumberWidget; + +/** + * Tests {@link Inputs}. + * + * @author Curtis Rueden + * @author Deborah Schmidt + */ +public class InputsTest { + + private Context context; + + @Before + public void setUp() { + context = new Context(); + context.service(PluginService.class); + } + + @After + public void tearDown() { + context.dispose(); + } + + /** Tests single input, no configuration. */ + @Test + public void testSingleInput() { + setExpected(new HashMap() {{ + put("sigma", 3.9f); + }}); + Inputs inputs = new Inputs(context); + inputs.getInfo().setName("testSingleInput");//TEMP + addTempInput(inputs, "sigma", Float.class); + float sigma = (Float) inputs.harvest().get("sigma"); + assertEquals(3.9f, sigma, 0); + } + + /** Tests two inputs, no configuration. */ + @Test + public void testTwoInputs() { + setExpected(new HashMap() {{ + put("name", "Chuckles"); + put("age", 37); + }}); + Inputs inputs = new Inputs(context); + inputs.getInfo().setName("testTwoInputs");//TEMP + addTempInput(inputs, "name", String.class); + addTempInput(inputs, "age", Integer.class); + Map values = inputs.harvest(); + String name = (String) values.get("name"); + int age = (Integer) values.get("age"); + assertEquals("Chuckles", name); + assertEquals(37, age); + } + + /** Tests inputs with configuration. */ + @Test + public void testWithConfiguration() { + setExpected(new HashMap() {{ + put("word", "brown"); + put("opacity", 0.8); + }}); + Inputs inputs = new Inputs(context); + inputs.getInfo().setName("testWithConfiguration");//TEMP + MutableModuleItem wordInput = addTempInput(inputs, "word", + String.class); + wordInput.setLabel("Favorite word"); + wordInput.setChoices(Arrays.asList("quick", "brown", "fox")); + wordInput.setDefaultValue("fox"); + MutableModuleItem opacityInput = addTempInput(inputs, "opacity", + Double.class); + opacityInput.setMinimumValue(0.0); + opacityInput.setMaximumValue(1.0); + opacityInput.setDefaultValue(0.5); + opacityInput.setWidgetStyle(NumberWidget.SCROLL_BAR_STYLE); + inputs.harvest(); + String word = wordInput.getValue(inputs); + double opacity = opacityInput.getValue(inputs); + assertEquals("brown", word); + assertEquals(0.8, opacity, 0); + } + + public void setExpected(final Map expected) { + final PluginInfo info = + new PluginInfo(MockInputHarvester.class, + PreprocessorPlugin.class) + { + @Override + public PreprocessorPlugin createInstance() throws InstantiableException { + final PreprocessorPlugin pp = super.createInstance(); + ((MockInputHarvester) pp).setExpected(expected); + return pp; + } + }; + info.setPriority(InputHarvester.PRIORITY); + context.service(PluginService.class).addPlugin(info); + } + + /** + * Add a non-persisted input to ensure we are testing with the mock input + * harvester. + */ + private static MutableModuleItem addTempInput(Inputs inputs, + String inputName, Class inputType) + { + MutableModuleItem input = inputs.addInput(inputName, inputType); + input.setPersisted(false); + return input; + } + + public static class MockInputHarvester extends AbstractPreprocessorPlugin { + private Map expected; + public void setExpected(final Map expected) { + this.expected = expected; + } + + @Override + public void process(final Module module) { + for (final ModuleItem input : module.getInfo().inputs()) { + if (module.isInputResolved(input.getName())) continue; + final String name = input.getName(); + if (!expected.containsKey(name)) { + throw new AssertionError("No value for input: " + input.getName()); + } + final Object value = expected.get(name); + module.setInput(name, value); + } + } + } +} diff --git a/src/test/java/org/scijava/command/InvalidCommandTest.java b/src/test/java/org/scijava/command/InvalidCommandTest.java index 2c4109a1e..e3f64b268 100644 --- a/src/test/java/org/scijava/command/InvalidCommandTest.java +++ b/src/test/java/org/scijava/command/InvalidCommandTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 7a226ed43..466df6426 100644 --- a/src/test/java/org/scijava/command/run/CommandCodeRunnerTest.java +++ b/src/test/java/org/scijava/command/run/CommandCodeRunnerTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 c87eadcb8..8a2760e85 100644 --- a/src/test/java/org/scijava/console/ConsoleServiceTest.java +++ b/src/test/java/org/scijava/console/ConsoleServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -86,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 b9ebff3d7..a45c7823e 100644 --- a/src/test/java/org/scijava/console/SystemPropertyArgumentTest.java +++ b/src/test/java/org/scijava/console/SystemPropertyArgumentTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 99505256c..8e7aac26b 100644 --- a/src/test/java/org/scijava/convert/AbstractNumberConverterTests.java +++ b/src/test/java/org/scijava/convert/AbstractNumberConverterTests.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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..0d1f7ef28 --- /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 - 2025 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 b08cfeb84..228ff9e3b 100644 --- a/src/test/java/org/scijava/convert/BigIntegerToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/BigIntegerToBigDecimalConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 bac9855af..638b0caf0 100644 --- a/src/test/java/org/scijava/convert/ByteToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToBigDecimalConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 2356d46c4..381b2f5ac 100644 --- a/src/test/java/org/scijava/convert/ByteToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToBigIntegerConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 fec333605..43d2c62ef 100644 --- a/src/test/java/org/scijava/convert/ByteToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToDoubleConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 8044c7f00..286f358a5 100644 --- a/src/test/java/org/scijava/convert/ByteToFloatConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToFloatConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 506a11fe9..f4607db21 100644 --- a/src/test/java/org/scijava/convert/ByteToIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToIntegerConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 79f58a1a0..38ffd40aa 100644 --- a/src/test/java/org/scijava/convert/ByteToLongConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToLongConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 284c485d7..c1e542e12 100644 --- a/src/test/java/org/scijava/convert/ByteToShortConverterTest.java +++ b/src/test/java/org/scijava/convert/ByteToShortConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 50debdabe..80fe29337 100644 --- a/src/test/java/org/scijava/convert/ConvertServiceTest.java +++ b/src/test/java/org/scijava/convert/ConvertServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,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; @@ -71,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; @@ -90,6 +85,7 @@ public class ConvertServiceTest { @Before public void setUp() { + @SuppressWarnings("resource") final Context context = new Context(ConvertService.class); convertService = context.getService(ConvertService.class); } @@ -158,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<>(); @@ -223,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)); } @@ -338,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)); } /** @@ -401,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)); } /** @@ -460,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]); } /** @@ -477,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]); } /** @@ -726,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); } } @@ -739,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 3a89f4785..cf9564346 100644 --- a/src/test/java/org/scijava/convert/ConverterTest.java +++ b/src/test/java/org/scijava/convert/ConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -60,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..af04d34ad --- /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 - 2025 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 new file mode 100644 index 000000000..ec1f4187c --- /dev/null +++ b/src/test/java/org/scijava/convert/DelegateConverterTest.java @@ -0,0 +1,146 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.plugin.Plugin; + + +public class DelegateConverterTest { + private Context context; + + @Before + public void setUp() { + context = new Context(); + } + + @After + public void tearDown() { + context.dispose(); + context = null; + } + + @Test + public void testDelegateConverters() { + ConvertService convertService = context.getService(ConvertService.class); + + // Test conversion from AType to BType + AType a = new AType(); + assertTrue(convertService.supports(a, BType.class)); + BType b = convertService.convert(a, BType.class); + assertSame(BType.class, b.getClass()); + + // Test conversion from BType to CType + assertTrue(convertService.supports(b, CType.class)); + CType c = convertService.convert(b, CType.class); + assertSame(CType.class, c.getClass()); + + // Test chained conversion + assertTrue(convertService.supports(a, CType.class)); + CType converted = convertService.convert(a, CType.class); + assertSame(c.getClass(), converted.getClass()); + } + + public static class AType { + // empty class + } + + public static class BType { + // empty class + } + + public static class CType { + // empty class + } + + @Plugin(type=Converter.class) + public static class ABConverter extends AbstractConverter { + + @SuppressWarnings("unchecked") + @Override + public T convert(Object src, Class dest) { + return (T) new BType(); + } + + @Override + public Class getOutputType() { + return BType.class; + } + + @Override + public Class getInputType() { + return AType.class; + } + } + + @Plugin(type=Converter.class) + public static class BCConverter extends AbstractConverter { + + @SuppressWarnings("unchecked") + @Override + public T convert(Object src, Class dest) { + return (T) new CType(); + } + + @Override + public Class getOutputType() { + return CType.class; + } + + @Override + public Class getInputType() { + return BType.class; + } + } + + @Plugin(type=Converter.class) + public static class DelegateConverter extends AbstractDelegateConverter { + + @Override + public Class getOutputType() { + return CType.class; + } + + @Override + public Class getInputType() { + return AType.class; + } + + @Override + protected Class getDelegateType() { + return BType.class; + } + } +} diff --git a/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java b/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java index d18d7b19a..ff6714dba 100644 --- a/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/DoubleToBigDecimalConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 ed3610e11..f5b40b2e4 100644 --- a/src/test/java/org/scijava/convert/FileListConverterTest.java +++ b/src/test/java/org/scijava/convert/FileListConverterTest.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 @@ -72,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..7fd087514 --- /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 - 2025 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 31085d0c6..7d49b6878 100644 --- a/src/test/java/org/scijava/convert/FloatToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/FloatToBigDecimalConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 2d836e667..45c5c4dfb 100644 --- a/src/test/java/org/scijava/convert/FloatToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/FloatToDoubleConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 44e85680f..4c375dcb8 100644 --- a/src/test/java/org/scijava/convert/IntegerToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToBigDecimalConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 9779a0a29..79c89bcb1 100644 --- a/src/test/java/org/scijava/convert/IntegerToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToBigIntegerConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 0f2c38533..0e1106536 100644 --- a/src/test/java/org/scijava/convert/IntegerToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToDoubleConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 fa242dd9b..5611b7f26 100644 --- a/src/test/java/org/scijava/convert/IntegerToLongConverterTest.java +++ b/src/test/java/org/scijava/convert/IntegerToLongConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 a5f7e7402..436730ee2 100644 --- a/src/test/java/org/scijava/convert/LongToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/LongToBigDecimalConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 c04794cb9..ec8a1c3ca 100644 --- a/src/test/java/org/scijava/convert/LongToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/LongToBigIntegerConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 436f2098f..642008214 100644 --- a/src/test/java/org/scijava/convert/ShortToBigDecimalConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToBigDecimalConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 35be86ac7..bb39f8c50 100644 --- a/src/test/java/org/scijava/convert/ShortToBigIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToBigIntegerConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 9b5f91830..336001970 100644 --- a/src/test/java/org/scijava/convert/ShortToDoubleConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToDoubleConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 b6b16a4f2..d893478ca 100644 --- a/src/test/java/org/scijava/convert/ShortToFloatConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToFloatConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 407df7e84..df9c62daf 100644 --- a/src/test/java/org/scijava/convert/ShortToIntegerConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToIntegerConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 361438faf..a5803241a 100644 --- a/src/test/java/org/scijava/convert/ShortToLongConverterTest.java +++ b/src/test/java/org/scijava/convert/ShortToLongConverterTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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..c68ddd568 --- /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 - 2025 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 conv; + + @Before + public void setUp() { + conv = new StringToNumberConverter(); + } + + @Test + public void stringToByteTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, Byte.class)); + Assert.assertEquals(new Byte((byte) 0), conv.convert(s, Byte.class)); + } + + @Test + public void stringToPrimitiveByteTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, byte.class)); + Assert.assertEquals(0, (int) conv.convert(s, byte.class)); + } + + @Test + public void stringToShortTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, Short.class)); + Assert.assertEquals(new Short((short) 0), conv.convert(s, Short.class)); + } + + @Test + public void stringToPrimitiveShortTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, short.class)); + Assert.assertEquals(0, (int) conv.convert(s, short.class)); + } + + @Test + public void stringToIntegerTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, Integer.class)); + Assert.assertEquals(new Integer(0), conv.convert(s, Integer.class)); + } + + @Test + public void stringToPrimitiveIntegerTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, int.class)); + Assert.assertEquals(0, (int) conv.convert(s, int.class)); + } + + @Test + public void stringToLongTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, Long.class)); + Assert.assertEquals(new Long(0), conv.convert(s, Long.class)); + } + + @Test + public void stringToPrimitiveLongTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, long.class)); + Assert.assertEquals(0L, (long) conv.convert(s, long.class)); + } + + @Test + public void stringToFloatTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, Float.class)); + Assert.assertEquals(new Float(0), conv.convert(s, Float.class)); + } + + @Test + public void stringToPrimitiveFloat() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, float.class)); + Assert.assertEquals(0f, conv.convert(s, float.class), 1e-6); + } + + @Test + public void stringToDoubleTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, Double.class)); + Assert.assertEquals(new Double(0), conv.convert(s, Double.class)); + } + + @Test + public void stringToPrimitiveDouble() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, double.class)); + Assert.assertEquals(0d, conv.convert(s, double.class), 1e-6); + } + + @Test + public void stringToNumberTest() { + String s = "0"; + Assert.assertTrue(conv.canConvert(s, Number.class)); + Assert.assertEquals(0d, conv.convert(s, Number.class)); + } + + @Test + public void invalidStringToNumberTest() { + String s = "invalid"; + Assert.assertFalse(conv.canConvert(s, Number.class)); + Assert.assertThrows(IllegalArgumentException.class, () -> conv.convert(s, + Number.class)); + } +} diff --git a/src/test/java/org/scijava/display/DisplayTest.java b/src/test/java/org/scijava/display/DisplayTest.java index 8b9081d6c..3d6f65de2 100644 --- a/src/test/java/org/scijava/display/DisplayTest.java +++ b/src/test/java/org/scijava/display/DisplayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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/download/DownloadServiceTest.java b/src/test/java/org/scijava/download/DownloadServiceTest.java index d7ca11eb8..a9bb2a421 100644 --- a/src/test/java/org/scijava/download/DownloadServiceTest.java +++ b/src/test/java/org/scijava/download/DownloadServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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/event/EventServiceTest.java b/src/test/java/org/scijava/event/EventServiceTest.java index a90e6adb0..de8c2b028 100644 --- a/src/test/java/org/scijava/event/EventServiceTest.java +++ b/src/test/java/org/scijava/event/EventServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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/event/bushe/BadEventService.java b/src/test/java/org/scijava/event/bushe/BadEventService.java new file mode 100644 index 000000000..2046821a2 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/BadEventService.java @@ -0,0 +1,10 @@ +package org.scijava.event.bushe; + +public class BadEventService extends ThreadSafeEventService { + + + /** @see org.scijava.event.bushe.EventService#subscribe(String,org.scijava.event.bushe.EventTopicSubscriber) */ + public boolean subscribe(String topic, EventTopicSubscriber eh) { + throw new RuntimeException("For testing"); + } +} diff --git a/src/test/java/org/scijava/event/bushe/DataRequestEvent.java b/src/test/java/org/scijava/event/bushe/DataRequestEvent.java new file mode 100644 index 000000000..236b44fa8 --- /dev/null +++ b/src/test/java/org/scijava/event/bushe/DataRequestEvent.java @@ -0,0 +1,9 @@ +package org.scijava.event.bushe; + +import java.util.List; + +/** + * Test event for Bill Wholer's typed events. + */ +public class DataRequestEvent { +} 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..3270287df --- /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 - 2025 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..6370089b5 --- /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 - 2025 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 acf5ec911..e57db1f3e 100644 --- a/src/test/java/org/scijava/io/ByteArrayByteBankTest.java +++ b/src/test/java/org/scijava/io/ByteArrayByteBankTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 60eaa7c1e..fd1ff0b6a 100644 --- a/src/test/java/org/scijava/io/ByteBankTest.java +++ b/src/test/java/org/scijava/io/ByteBankTest.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 diff --git a/src/test/java/org/scijava/io/IOServiceTest.java b/src/test/java/org/scijava/io/IOServiceTest.java new file mode 100644 index 000000000..bae4be289 --- /dev/null +++ b/src/test/java/org/scijava/io/IOServiceTest.java @@ -0,0 +1,81 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io; + +import org.junit.Test; +import org.scijava.Context; +import org.scijava.io.location.FileLocation; +import org.scijava.plugin.PluginInfo; +import org.scijava.text.AbstractTextFormat; +import org.scijava.text.TextFormat; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class IOServiceTest { + + @Test + public void testTextFile() throws IOException { + // create context, add dummy text format + final Context ctx = new Context(); + ctx.getPluginIndex().add(new PluginInfo<>(DummyTextFormat.class, TextFormat.class)); + final IOService io = ctx.getService(IOService.class); + + // open text file from resources as String + String localFile = getClass().getResource("test.txt").getPath(); + Object obj = io.open(localFile); + assertNotNull(obj); + String content = obj.toString(); + assertTrue(content.contains("content")); + + // open text file from resources as FileLocation + obj = io.open(new FileLocation(localFile)); + assertNotNull(obj); + assertEquals(content, obj.toString()); + } + + + public static class DummyTextFormat extends AbstractTextFormat { + + @Override + public List getExtensions() { + return Collections.singletonList("txt"); + } + + @Override + public String asHTML(String text) { + return text; + } + } +} diff --git a/src/test/java/org/scijava/io/TypedIOServiceTest.java b/src/test/java/org/scijava/io/TypedIOServiceTest.java new file mode 100644 index 000000000..d59cb9014 --- /dev/null +++ b/src/test/java/org/scijava/io/TypedIOServiceTest.java @@ -0,0 +1,77 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io; + +import org.junit.Test; +import org.scijava.Context; +import org.scijava.plugin.PluginInfo; +import org.scijava.text.AbstractTextFormat; +import org.scijava.text.TextFormat; +import org.scijava.text.io.TextIOService; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class TypedIOServiceTest { + + @Test + public void testTextFile() throws IOException { + // create context, add dummy text format + final Context ctx = new Context(); + ctx.getPluginIndex().add(new PluginInfo<>(DummyTextFormat.class, TextFormat.class)); + + // try to get the TextIOService + final TextIOService io = ctx.service(TextIOService.class); + assertNotNull(io); + + // open text file from resources as String + String localFile = getClass().getResource("test.txt").getPath(); + String obj = io.open(localFile); + assertNotNull(obj); + assertTrue(obj.contains("content")); + } + + public static class DummyTextFormat extends AbstractTextFormat { + + @Override + public List getExtensions() { + return Collections.singletonList("txt"); + } + + @Override + public String asHTML(String text) { + return text; + } + + } +} diff --git a/src/test/java/org/scijava/io/event/DataEventTest.java b/src/test/java/org/scijava/io/event/DataEventTest.java new file mode 100644 index 000000000..0c4e8e7ea --- /dev/null +++ b/src/test/java/org/scijava/io/event/DataEventTest.java @@ -0,0 +1,58 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.event; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; + +import org.junit.Test; + +public class DataEventTest { + + @Test + public void testDeprecatedMethods() throws IOException { + File tmpFile = File.createTempFile("path", "txt"); + tmpFile.deleteOnExit(); + String localPath = tmpFile.getAbsolutePath(); + Object obj = null; + DataOpenedEvent openedEvent = new DataOpenedEvent(localPath, obj); + DataSavedEvent savedEvent = new DataSavedEvent(localPath, obj); + assertEquals(localPath, openedEvent.getSource()); + assertEquals(localPath, savedEvent.getDestination()); + +// String remotepath = "https://remote.org/path.txt"; +// openedEvent = new DataOpenedEvent(remotepath, obj); +// savedEvent = new DataSavedEvent(remotepath, obj); +// assertEquals(remotepath, openedEvent.getSource()); +// assertEquals(remotepath, savedEvent.getDestination()); + } + +} diff --git a/src/test/java/org/scijava/io/handle/BytesHandleTest.java b/src/test/java/org/scijava/io/handle/BytesHandleTest.java index 03c536d55..a996b4fa2 100644 --- a/src/test/java/org/scijava/io/handle/BytesHandleTest.java +++ b/src/test/java/org/scijava/io/handle/BytesHandleTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 new file mode 100644 index 000000000..bac3ee2f2 --- /dev/null +++ b/src/test/java/org/scijava/io/handle/DataHandleEdgeCaseTests.java @@ -0,0 +1,139 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.handle; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.io.IOException; +import java.util.Arrays; + +import org.junit.Test; +import org.scijava.Context; +import org.scijava.io.location.BytesLocation; +import org.scijava.io.location.Location; + +/** + * Additional Tests for edge case behavior of {@link DataHandle}. + * + * @author Gabriel Einsdorf + */ +public class DataHandleEdgeCaseTests { + + private static final byte[] BYTES = { // + 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', // + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -128, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // + 125, 127, -127, -125, -3, 'h', 'e' }; + + /** + * Test to ensure {@link DataHandle#findString(String...)} and + * {@link DataHandle#readCString()} work with {@link DataHandle} + * implementations that have unknown length. + * + * @throws IOException + */ + @Test + public void testFindStringsOnUnknonwLengthHandle() throws IOException { + final Context ctx = new Context(); + final DataHandleService dhs = ctx.getService(DataHandleService.class); + final DummyHandle dummy = new DummyHandle(dhs.create(new BytesLocation( + BYTES))); + + assertEquals("Hello,", dummy.findString(",")); + assertEquals(" world\n", dummy.findString("\n")); + + dummy.seek(41); + assertEquals("he", dummy.findString("\n")); + + dummy.seek(16); + assertArrayEquals(Arrays.copyOfRange(BYTES, 16, 23), dummy.readCString() + .getBytes()); + dummy.seek(42); + assertNull(dummy.readCString()); + } + + private class DummyHandle extends AbstractHigherOrderHandle { + + public DummyHandle(final DataHandle handle) { + super(handle); + } + + @Override + public long length() throws IOException { + return -1; + } + + @Override + public long offset() throws IOException { + return handle().offset(); + } + + @Override + public void seek(final long pos) throws IOException { + handle().seek(pos); + } + + @Override + public void setLength(final long length) throws IOException { + handle().setLength(length); + } + + @Override + public int read(final byte[] b, final int off, final int len) + throws IOException + { + return handle().read(b, off, len); + } + + @Override + public byte readByte() throws IOException { + return handle().readByte(); + } + + @Override + public void write(final int b) throws IOException { + handle().write(b); + } + + @Override + public void write(final byte[] b, final int off, final int len) + throws IOException + { + handle().write(b, off, len); + } + + @Override + protected void cleanup() throws IOException { + // + } + } + +} diff --git a/src/test/java/org/scijava/io/handle/DataHandleTest.java b/src/test/java/org/scijava/io/handle/DataHandleTest.java index f15248c7c..8e84c4087 100644 --- a/src/test/java/org/scijava/io/handle/DataHandleTest.java +++ b/src/test/java/org/scijava/io/handle/DataHandleTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,16 +30,19 @@ package org.scijava.io.handle; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; +import java.util.function.Supplier; +import org.junit.Before; import org.junit.Test; import org.scijava.Context; -import org.scijava.io.handle.DataHandle; import org.scijava.io.handle.DataHandle.ByteOrder; -import org.scijava.io.handle.DataHandleService; import org.scijava.io.location.Location; import org.scijava.util.Bytes; @@ -55,29 +55,78 @@ public abstract class DataHandleTest { protected static final byte[] BYTES = { // 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', // - 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -128, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // - 125, 127, -127, -125, -3, -2, -1 }; + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -128, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // + 125, 127, -127, -125, -3, -2, -1 }; - // -- Test methods -- + protected DataHandleService dataHandleService; - @Test - public void testDataHandle() throws IOException { + @Before + public void init() { final Context context = new Context(DataHandleService.class); - final DataHandleService dataHandleService = - context.service(DataHandleService.class); + dataHandleService = context.service(DataHandleService.class); + } + + @Test + public void checkSkip() throws IOException { + try (final DataHandle handle = createHandle()) { + handle.seek(0); + handle.skip(10); + assertEquals(10, handle.offset()); + handle.skipBytes(11); + assertEquals(21, handle.offset()); + } + } + + @Test + public void testEndianesSettings() throws IOException { + + try (final DataHandle handle = createHandle()) { + final ByteOrder original = handle.getOrder(); - final Location loc = createLocation(); - try (final DataHandle handle = // - dataHandleService.create(loc)) - { - assertEquals(getExpectedHandleType(), handle.getClass()); + handle.setOrder(ByteOrder.BIG_ENDIAN); + assertEquals(ByteOrder.BIG_ENDIAN, handle.getOrder()); + assertTrue(handle.isBigEndian()); + assertFalse(handle.isLittleEndian()); - checkReads(handle); - checkWrites(handle); + handle.setOrder(ByteOrder.LITTLE_ENDIAN); + assertEquals(ByteOrder.LITTLE_ENDIAN, handle.getOrder()); + assertFalse(handle.isBigEndian()); + assertTrue(handle.isLittleEndian()); + + handle.setLittleEndian(false); + assertEquals(ByteOrder.BIG_ENDIAN, handle.getOrder()); + assertTrue(handle.isBigEndian()); + assertFalse(handle.isLittleEndian()); + + handle.setLittleEndian(true); + assertEquals(ByteOrder.LITTLE_ENDIAN, handle.getOrder()); + assertFalse(handle.isBigEndian()); + assertTrue(handle.isLittleEndian()); + + handle.setOrder(original); + } + } + + @Test + public void testReading() throws IOException { + try (final DataHandle handle = createHandle()) { + checkBasicReadMethods(handle, true); + checkEndiannessReading(handle); } } - // -- DataHandleTest methods -- + @Test + public void testWriting() throws IOException { + try (final DataHandle handle = createHandle()) { + checkBasicWriteMethods(handle); + final Location loc = createLocation(); + checkWriteEndianes(() -> dataHandleService.create(loc), + ByteOrder.LITTLE_ENDIAN); + checkWriteEndianes(() -> dataHandleService.create(loc), + ByteOrder.BIG_ENDIAN); + checkAdvancedStringWriting(() -> dataHandleService.create(loc)); + } + } public abstract Class> getExpectedHandleType(); @@ -85,19 +134,46 @@ public void testDataHandle() throws IOException { // -- Internal methods -- - protected void populateData(final OutputStream out) throws IOException { + /** + * Creates a handle for testing + */ + public DataHandle createHandle() { + Location loc; + try { + loc = createLocation(); + } + catch (final IOException exc) { + throw new RuntimeException(exc); + } + final DataHandle handle = dataHandleService.create(loc); + assertEquals(getExpectedHandleType(), handle.getClass()); + return handle; + } + + /** + * Populates the provided {@link OutputStream} with test data. + * + * @param out the {@link OutputStream} to fill + * @throws IOException + */ + public void populateData(final OutputStream out) throws IOException { out.write(BYTES); out.close(); } - protected void checkReads(final DataHandle handle) - throws IOException + /** + * Checks basic byte reading methods. + * + * @param handle the handle to test + * @param lengthKnown whether the length of the handle is know + * @throws IOException + */ + public void checkBasicReadMethods( + final DataHandle handle, boolean lengthKnown) throws IOException { assertEquals(0, handle.offset()); - assertEquals(BYTES.length, handle.length()); + assertEquals(lengthKnown ? BYTES.length : -1, handle.length()); assertEquals("UTF-8", handle.getEncoding()); - assertEquals(ByteOrder.BIG_ENDIAN, handle.getOrder()); - assertEquals(false, handle.isLittleEndian()); // test read() for (int i = 0; i < BYTES.length; i++) { @@ -119,98 +195,373 @@ protected void checkReads(final DataHandle handle) assertEquals(msg(i), BYTES[i], handle.readByte()); } + // test readUnsignedByte() + handle.seek(0); + for (int i = 0; i < BYTES.length; i++) { + assertEquals(msg(i), BYTES[i] & 0xff, handle.readUnsignedByte()); + } + + // test readFully(byte[]) + Arrays.fill(buf, (byte) 0); + handle.seek(3); + handle.readFully(buf); + assertBytesMatch(3, buf.length, buf); + + // test readCString() - _includes_ the null terminator! + handle.seek(16); + assertBytesMatch(16, 7, handle.readCString().getBytes()); + handle.seek(42); + assertNull(handle.readCString()); + + // test readBoolean + handle.seek(21); + assertTrue(handle.readBoolean()); + assertFalse(handle.readBoolean()); + + // test readLine() - _excludes_ the newline terminator! + handle.seek(7); + assertBytesMatch(7, 5, handle.readLine().getBytes()); + + // test readString(String) - _includes_ the matching terminator! + handle.seek(7); + assertBytesMatch(7, 5, handle.readString("abcdefg").getBytes()); + + // test readString() + handle.seek(7); + assertBytesMatch(7, 5, handle.readString("d").getBytes()); + + // test readString(int + handle.seek(7); + assertBytesMatch(7, 5, handle.readString(5).getBytes()); + + // test findString(String) - _includes_ the matching terminator! + handle.seek(1); + assertBytesMatch(1, 11, handle.findString("world").getBytes()); + + handle.seek(0); + handle.findString(false, "world"); + assertEquals(12, handle.offset()); + + handle.seek(0); + handle.findString(false, "w"); + assertEquals(8, handle.offset()); + } + + /** + * Checks reading methods effected by endianness. Tests both + * {@link ByteOrder#LITTLE_ENDIAN} and {@link ByteOrder#BIG_ENDIAN}. + * + * @param handle the handle to check + * @throws IOException + */ + public void checkEndiannessReading( + final DataHandle handle) throws IOException + { + checkEndiannessReading(handle, ByteOrder.LITTLE_ENDIAN); + checkEndiannessReading(handle, ByteOrder.BIG_ENDIAN); + } + + /** + * Checks reading methods effected by endianness. + * + * @param handle the handle to check + * @param order the {@link ByteOrder} to check + * @throws IOException + */ + public void checkEndiannessReading( + final DataHandle handle, final ByteOrder order) + throws IOException + { + handle.setOrder(order); + handle.seek(0); + final boolean little = order == ByteOrder.LITTLE_ENDIAN; + + // test readChar() + + handle.seek(0); + for (int i = 0; i < BYTES.length / 2; i += 2) { + assertEquals(msg(i), (char) Bytes.toShort(BYTES, i, little), handle + .readChar()); + } + // test readShort() handle.seek(0); for (int i = 0; i < BYTES.length / 2; i += 2) { - assertEquals(msg(i), Bytes.toShort(BYTES, i, false), handle.readShort()); + assertEquals(msg(i), Bytes.toShort(BYTES, i, little), handle.readShort()); } // test readInt() handle.seek(0); for (int i = 0; i < BYTES.length / 4; i += 4) { - assertEquals(msg(i), Bytes.toInt(BYTES, i, false), handle.readInt()); + assertEquals(msg(i), Bytes.toInt(BYTES, i, little), handle.readInt()); } // test readLong() handle.seek(0); for (int i = 0; i < BYTES.length / 8; i += 8) { - assertEquals(msg(i), Bytes.toLong(BYTES, i, false), handle.readLong()); + assertEquals(msg(i), Bytes.toLong(BYTES, i, little), handle.readLong()); } // test readFloat() handle.seek(0); for (int i = 0; i < BYTES.length / 4; i += 4) { - assertEquals(msg(i), Bytes.toFloat(BYTES, i, false), handle.readFloat(), + assertEquals(msg(i), Bytes.toFloat(BYTES, i, little), handle.readFloat(), 0); } // test readDouble() handle.seek(0); for (int i = 0; i < BYTES.length / 8; i += 8) { - assertEquals(msg(i), Bytes.toDouble(BYTES, i, false), - handle.readDouble(), 0); - } - - // test readBoolean() - handle.seek(0); - for (int i = 0; i < BYTES.length; i++) { - assertEquals(msg(i), BYTES[i] == 0 ? false : true, handle.readBoolean()); + assertEquals(msg(i), Bytes.toDouble(BYTES, i, little), handle + .readDouble(), 0); } + } - // test readChar() - handle.seek(0); - for (int i = 0; i < BYTES.length / 2; i += 2) { - assertEquals(msg(i), (char) Bytes.toInt(BYTES, i, 2, false), handle - .readChar()); - } - - // test readFully(byte[]) - Arrays.fill(buf, (byte) 0); - handle.seek(3); - handle.readFully(buf); - assertBytesMatch(3, buf.length, buf); - - // test readCString() - _includes_ the null terminator! - handle.seek(16); - assertBytesMatch(16, 7, handle.readCString().getBytes()); - - // test readLine() - _excludes_ the newline terminator! - handle.seek(7); - assertBytesMatch(7, 5, handle.readLine().getBytes()); - - // test readString(String) - _includes_ the matching terminator! - handle.seek(7); - assertBytesMatch(7, 5, handle.readString("abcdefg").getBytes()); - - // test findString(String) - _includes_ the matching terminator! - handle.seek(1); - assertBytesMatch(1, 11, handle.findString("world").getBytes()); + /** + * Check basic write methods for bytes. + * + * @param handle the handle to write to and read from + * @throws IOException + */ + public void checkBasicWriteMethods( + final DataHandle handle) throws IOException + { + checkBasicWrites(handle, handle); } - protected void checkWrites(final DataHandle handle) + /** + * Tests basic write methods for bytes, both provided handles must point to + * the same location! + * + * @param readHandle the handle to read from + * @param writeHandle the handle to write from + * @throws IOException + */ + public void checkBasicWrites( + final DataHandle readHandle, final DataHandle writeHandle) throws IOException { final byte[] copy = BYTES.clone(); // change the data - handle.seek(7); + writeHandle.seek(7); final String splice = "there"; for (int i = 0; i < splice.length(); i++) { final char c = splice.charAt(i); - handle.write(c); + writeHandle.write(c); copy[7 + i] = (byte) c; } + writeHandle.writeBoolean(true); + copy[12] = 1; + writeHandle.writeBoolean(false); + copy[13] = 0; + + writeHandle.writeByte(42); + copy[14] = 42; + + if (writeHandle != readHandle) { + writeHandle.close(); // to ensure data is flushed + } + // verify the changes - handle.seek(0); + readHandle.seek(0); for (int i = 0; i < copy.length; i++) { - assertEquals(msg(i), 0xff & copy[i], handle.read()); + assertEquals(msg(i), 0xff & copy[i], readHandle.read()); + } + } + + /** + * Checks advanced string writing methods. + * + * @param handleCreator a supplier that creates properly initialized handles + * for reading and writing, all created handles must point to the + * same location! + * @throws IOException + */ + public void checkAdvancedStringWriting( + final Supplier> handleCreator) throws IOException + { + checkAdvancedStringWriting(handleCreator, handleCreator); + } + + /** + * Checks advanced string writing methods. + * + * @param readHandleCreator a supplier that creates properly initialized + * handles for reading, all created handles must point to the same + * location! + * @param writeHandleCreator a supplier that creates properly initialized + * handles for reading, all created handles must point to the same + * location! + * @throws IOException + */ + public void checkAdvancedStringWriting( + final Supplier> readHandleCreator, + final Supplier> writeHandleCreator) throws IOException + { + // test writeUTF() / readUTF() + final String utfTestString = "abc\u00E4\u00FA\u00F6\u00E4" + + "\u00E9\u00EB\u00E5\u00E1\u00F0\u00DF\u00EF\u0153\u0153" + + "\u00F8\u00B6\uD83E\uDD13\uD83C\uDF55\uD83D\uDE0B"; + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.writeUTF(utfTestString); + } + try (final DataHandle readHandle = readHandleCreator.get()) { + assertEquals(utfTestString, readHandle.readUTF()); + } + + // test writeLine() + final String testString = "The quick brown fox jumps over the lazy dog."; + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.writeLine(testString); + } + try (final DataHandle readHandle = readHandleCreator.get()) { + assertEquals(testString, readHandle.readLine()); + } + + // test writeChars / findString + final String testString2 = "The five boxing wizards jump quickly."; + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.writeChars(testString2); + } + try (final DataHandle readHandle = readHandleCreator.get()) { + for (int i = 0; i < testString2.length(); i++) { + assertEquals(testString2.charAt(i), readHandle.readChar()); + } + } + } + + /** + * Checks writing methods affected by endianness. + * + * @param handleCreator a supplier that creates properly initialized + * handles. All created handles must point to the same + * location! + * @param order Byte order to use when writing to the handles. + */ + public void checkWriteEndianes( + final Supplier> handleCreator, final ByteOrder order) + throws IOException + { + checkWriteEndianes(handleCreator, handleCreator, order); + } + + /** + * Checks writing methods affected by endianness. + * + * @param readHandleCreator a supplier that creates properly initialized + * handles for reading. All created handles must point to the same + * location! + * @param writeHandleCreator a supplier that creates properly initialized + * handles for writing. All created handles must point to the same + * location! + * @param order Byte order to use when writing to the handles. + * @throws IOException + */ + public void checkWriteEndianes( + final Supplier> readHandleCreator, + final Supplier> writeHandleCreator, final ByteOrder order) + throws IOException + { + final boolean little = order == ByteOrder.LITTLE_ENDIAN; + + // test writeChar() + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 2; i += 2) { + writeHandle.writeChar(Bytes.toInt(BYTES, i, 2, little)); + } + } + + try (final DataHandle readHandle = readHandleCreator.get()) { + readHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 2; i += 2) { + assertEquals(msg(i), Bytes.toShort(BYTES, i, little), readHandle + .readChar()); + } + } + + // test writeShort() + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 2; i += 2) { + writeHandle.writeShort(Bytes.toShort(BYTES, i, little)); + } + } + + try (final DataHandle readHandle = readHandleCreator.get()) { + readHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 2; i += 2) { + assertEquals(msg(i), Bytes.toShort(BYTES, i, little), readHandle + .readShort()); + } + } + + // test writeInt() + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 4; i += 4) { + writeHandle.writeInt(Bytes.toInt(BYTES, i, little)); + } + } + try (final DataHandle readHandle = readHandleCreator.get()) { + readHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 4; i += 4) { + assertEquals(msg(i), Bytes.toInt(BYTES, i, little), readHandle + .readInt()); + } + } + + // test writeLong() + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 8; i += 8) { + writeHandle.writeLong(Bytes.toLong(BYTES, i, little)); + } + } + try (final DataHandle readHandle = readHandleCreator.get()) { + readHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 8; i += 8) { + assertEquals(msg(i), Bytes.toLong(BYTES, i, little), readHandle + .readLong()); + } + } + + // test writeFloat() + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 4; i += 4) { + writeHandle.writeFloat(Bytes.toFloat(BYTES, i, little)); + } + } + try (final DataHandle readHandle = readHandleCreator.get()) { + readHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 4; i += 4) { + assertEquals(msg(i), Bytes.toFloat(BYTES, i, little), readHandle + .readFloat(), 0); + } + } + + // test writeDouble() + try (final DataHandle writeHandle = writeHandleCreator.get()) { + writeHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 8; i += 8) { + writeHandle.writeDouble(Bytes.toDouble(BYTES, i, little)); + } + } + try (final DataHandle readHandle = readHandleCreator.get()) { + readHandle.setOrder(order); + for (int i = 0; i < BYTES.length / 8; i += 8) { + assertEquals(msg(i), Bytes.toDouble(BYTES, i, little), readHandle + .readDouble(), 0); + } } } // -- Internal methods -- - protected void assertBytesMatch(final int offset, final int length, + public void assertBytesMatch(final int offset, final int length, final byte[] b) { assertEquals(length, b.length); @@ -219,7 +570,9 @@ protected void assertBytesMatch(final int offset, final int length, } } - protected String msg(final int i) { + // -- Test methods -- + + public String msg(final int i) { return "[" + i + "]:"; } diff --git a/src/test/java/org/scijava/io/handle/DataHandlesTest.java b/src/test/java/org/scijava/io/handle/DataHandlesTest.java index 4d2a9a8c6..5e0a95359 100644 --- a/src/test/java/org/scijava/io/handle/DataHandlesTest.java +++ b/src/test/java/org/scijava/io/handle/DataHandlesTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 0a51b4a14..6caa0c7e3 100644 --- a/src/test/java/org/scijava/io/handle/FileHandleTest.java +++ b/src/test/java/org/scijava/io/handle/FileHandleTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,10 +32,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.net.URI; import org.junit.Test; import org.scijava.Context; @@ -77,14 +76,15 @@ public void testExists() throws IOException { assertFalse(nonExistentFile.exists()); final FileLocation loc = new FileLocation(nonExistentFile); - final DataHandle handle = dhs.create(loc); - assertTrue(handle instanceof FileHandle); - assertFalse(handle.exists()); - assertEquals(-1, handle.length()); + try (final DataHandle handle = dhs.create(loc)) { + assertTrue(handle instanceof FileHandle); + assertFalse(handle.exists()); + assertEquals(-1, handle.length()); - handle.writeBoolean(true); - assertTrue(handle.exists()); - assertEquals(1, handle.length()); + handle.writeBoolean(true); + assertTrue(handle.exists()); + assertEquals(1, handle.length()); + } // Clean up. assertTrue(nonExistentFile.delete()); @@ -101,11 +101,34 @@ public void testNotCreatedByClose() throws IOException { assertFalse(nonExistentFile.exists()); final FileLocation loc = new FileLocation(nonExistentFile); - final DataHandle handle = dhs.create(loc); - assertTrue(handle instanceof FileHandle); - assertFalse(handle.exists()); + try (final DataHandle handle = dhs.create(loc)) { + assertTrue(handle instanceof FileHandle); + assertFalse(handle.exists()); + } + assertFalse(nonExistentFile.exists()); + } + + @Test + public void testNotCreatedByRead() throws IOException { + final Context ctx = new Context(); + final DataHandleService dhs = ctx.service(DataHandleService.class); + + final File nonExistentFile = // + File.createTempFile("FileHandleTest", "none xistent file"); + final URI uri = nonExistentFile.toURI(); + assertTrue(nonExistentFile.delete()); + assertFalse(nonExistentFile.exists()); - handle.close(); + final FileLocation loc = new FileLocation(uri); + try (final DataHandle handle = dhs.create(loc)) { + assertFalse(handle.exists()); + handle.read(); // this will fail as there is no underlying file! + fail("Read successfully from non-existing file!"); + } + catch (final IOException exc) { + // should be thrown + } assertFalse(nonExistentFile.exists()); + // reading from the non-existing file should not create it! } } diff --git a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java index cc1b992d2..3337d4a82 100644 --- a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java +++ b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleMockTest.java @@ -1,21 +1,53 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.io.handle; -import org.junit.Before; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; import org.scijava.io.location.DummyLocation; import org.scijava.io.location.Location; -import static org.mockito.Mockito.*; - -import java.io.IOException; - public class ReadBufferDataHandleMockTest { private DataHandle mock; @@ -59,34 +91,40 @@ public void testBufferingSequence() throws IOException { // set length of stubbed handle when(mock.length()).thenReturn(30l); + byte[] value = new byte[10]; + when(mock.read(aryEq(value), eq(0), eq(10))).thenReturn(10); + when(mock.read(aryEq(value), anyInt(), anyInt())).thenReturn(10); // read the first byte buf.read(); verify(mock, times(0)).seek(0); // buffer should read a whole page - verify(mock).read(aryEq(byteArrayLen10)); + verify(mock).read(aryEq(byteArrayLen10), eq(0), eq(10)); buf.seek(0); // ensure seek was not called again verify(mock, times(0)).seek(0); + when(mock.offset()).thenReturn(10l); + // read over the edge of the current page buf.read(new byte[12]); verify(mock, times(0)).seek(anyLong()); - verify(mock, times(2)).read(aryEq(byteArrayLen10)); + verify(mock, times(2)).read(aryEq(byteArrayLen10), eq(0), eq(10)); assertEquals(12, buf.offset()); // read the last page + when(mock.offset()).thenReturn(20l); buf.read(new byte[12]); verify(mock, times(0)).seek(anyLong()); - verify(mock, times(3)).read(aryEq(byteArrayLen10)); + verify(mock, times(3)).read(aryEq(byteArrayLen10), eq(0), eq(10)); // first page should no longer be buffered, must be reread in buf.seek(0); buf.read(); verify(mock).seek(0); - verify(mock, times(4)).read(aryEq(byteArrayLen10)); + verify(mock, times(4)).read(aryEq(byteArrayLen10), eq(0), eq(10)); } /** @@ -99,11 +137,12 @@ public void testSkipForward() throws IOException { // set length of stubbed handle when(mock.length()).thenReturn(40l); + when(mock.read(any(), anyInt(), anyInt())).thenReturn(10); // read the first byte buf.read(); verify(mock, times(0)).seek(anyLong()); - verify(mock).read(aryEq(byteArrayLen10)); + verify(mock, times(1)).read(aryEq(byteArrayLen10), eq(0), eq(10)); // skip the second page buf.seek(30l); @@ -111,7 +150,8 @@ public void testSkipForward() throws IOException { // read the third page verify(mock).seek(30l); - verify(mock, times(2)).read(aryEq(byteArrayLen10)); + verify(mock, times(2)).read(aryEq(byteArrayLen10), eq(0), eq(10)); + when(mock.offset()).thenReturn(40l); // go back to already buffered page buf.seek(0l); @@ -123,6 +163,6 @@ public void testSkipForward() throws IOException { buf.seek(35); buf.read(); verify(mock, times(1)).seek(anyLong()); - verify(mock, times(2)).read(any()); + verify(mock, times(2)).read(any(), anyInt(), anyInt()); } } diff --git a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java index a2a987a5e..5e0fce0df 100644 --- a/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java +++ b/src/test/java/org/scijava/io/handle/ReadBufferDataHandleTest.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 @@ -42,9 +39,8 @@ import java.util.List; import java.util.Random; -import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; -import org.scijava.Context; import org.scijava.io.location.BytesLocation; import org.scijava.io.location.Location; @@ -55,35 +51,40 @@ */ public class ReadBufferDataHandleTest extends DataHandleTest { - private Context context; - private DataHandleService dataHandleService; - - @Override @Test - public void testDataHandle() throws IOException { + public void testSmallBuffer() throws IOException { final Location loc = createLocation(); try (final DataHandle handle = // dataHandleService.create(loc); AbstractDataHandle bufferedHandle = // - new ReadBufferDataHandle(handle)) + new ReadBufferDataHandle(handle, 5)) { - checkReads(bufferedHandle); + // check with small buffersize + checkBasicReadMethods(bufferedHandle, true); + checkEndiannessReading(bufferedHandle); } } - @Test - public void testSmallBuffer() throws IOException { + @Test(expected = IOException.class) + public void ensureNotWritable() throws IOException { + createHandle().write(1); + } - final Location loc = createLocation(); - try (final DataHandle handle = // - dataHandleService.create(loc); - AbstractDataHandle bufferedHandle = // - new ReadBufferDataHandle(handle, 5)) - { - // check with small buffersize - checkReads(bufferedHandle); + @Override + public DataHandle createHandle() { + Location loc; + try { + loc = createLocation(); } + catch (final IOException exc) { + throw new RuntimeException(exc); + } + final DataHandle handle = // + dataHandleService.create(loc); + final AbstractDataHandle bufferedHandle = // + new ReadBufferDataHandle(handle, 5); + return bufferedHandle; } @Test @@ -91,7 +92,7 @@ public void testLargeRead() throws Exception { final int size = 10_00; final byte[] bytes = new byte[size]; - Random r = new Random(42); + final Random r = new Random(42); r.nextBytes(bytes); final Location loc = new BytesLocation(bytes); @@ -104,34 +105,33 @@ public void testLargeRead() throws Exception { final byte[] actual = new byte[size]; // create evenly sized slice ranges - int slices = 60; - int range = (size + slices - 1) / slices; - List> ranges = new ArrayList<>(); + final int slices = 60; + final int range = (size + slices - 1) / slices; + final List> ranges = new ArrayList<>(); for (int i = 0; i < slices; i++) { - int start = range * i; - int end = range * (i + 1); + final int start = range * i; + final int end = range * (i + 1); ranges.add(new SimpleEntry<>(start, end)); } Collections.shuffle(ranges, r); - for (SimpleEntry e : ranges) { + for (final SimpleEntry e : ranges) { bufferedHandle.seek(e.getKey()); bufferedHandle.read(actual, e.getKey(), e.getValue() - e.getKey()); } - assertArrayEquals(bytes, actual); } } - @Before - public void setup() { - context = new Context(DataHandleService.class); - dataHandleService = context.service(DataHandleService.class); + @Test + @Override + public void testWriting() throws IOException { + // nothing to do here } @Override public Class> getExpectedHandleType() { - return null; + throw new UnsupportedOperationException(); } @Override diff --git a/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java b/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java index b17d4037a..dd0c158f4 100644 --- a/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java +++ b/src/test/java/org/scijava/io/handle/WriteBufferDataHandleTest.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 @@ -32,78 +29,82 @@ package org.scijava.io.handle; -import static org.junit.Assert.assertEquals; - import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.function.Supplier; +import org.junit.Ignore; import org.junit.Test; -import org.scijava.Context; +import org.scijava.io.handle.DataHandle.ByteOrder; import org.scijava.io.location.BytesLocation; import org.scijava.io.location.Location; public class WriteBufferDataHandleTest extends DataHandleTest { - private Location loc; - @Override public Class> getExpectedHandleType() { // not needed - return null; + throw new UnsupportedOperationException(); } @Override - @Test - public void testDataHandle() throws IOException { - final Context context = new Context(DataHandleService.class); - final DataHandleService dataHandleService = context.service( - DataHandleService.class); + public Location createLocation() throws IOException { + // not needed + throw new UnsupportedOperationException(); + } - loc = createLocation(); - try (final DataHandle handle = // - dataHandleService.create(loc); - final DataHandle buffer = // - new WriteBufferDataHandle(handle)) - { - checkWrites(buffer); - } + @Override + public DataHandle createHandle() { + final DataHandle handle = // + dataHandleService.create(new BytesLocation(new byte[42])); + return dataHandleService.writeBuffer(handle); } + @Test @Override - public Location createLocation() throws IOException { + public void testReading() throws IOException { + // nothing to do + } + + @Test + @Override + public void checkSkip() throws IOException { + // nothing to do + } - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - populateData(out); - return new BytesLocation(out.toByteArray()); + @Test(expected = IOException.class) + public void ensureNotReadable() throws IOException { + createHandle().read(); } @Override - protected void checkWrites(final DataHandle handle) - throws IOException - { - final byte[] copy = BYTES.clone(); + @Test + public void testWriting() throws IOException { + final ByteArrayOutputStream os = new ByteArrayOutputStream(42); + populateData(os); + final BytesLocation location = new BytesLocation(os.toByteArray()); + final DataHandle handle = // + dataHandleService.create(location); + final DataHandle writeHandle = dataHandleService.writeBuffer( + handle); - // change the data - handle.seek(7); - final String splice = "there"; - for (int i = 0; i < splice.length(); i++) { - final char c = splice.charAt(i); - handle.write(c); - copy[7 + i] = (byte) c; - } - handle.close(); + checkBasicWrites(handle, writeHandle); + } - final Context context = new Context(DataHandleService.class); - final DataHandleService dataHandleService = context.service( - DataHandleService.class); + @Test + public void testEndiannessWriting() throws IOException { + final BytesLocation location = new BytesLocation(new byte[42]); + final Supplier> readHandleSupplier = + () -> dataHandleService.create(location); + final Supplier> writeHandleSupplier = () -> { + final DataHandle h = dataHandleService.create(location); + return dataHandleService.writeBuffer(h); + }; - try (final DataHandle readHandle = // - dataHandleService.create(loc)) - { - readHandle.seek(0); - for (int i = 0; i < copy.length; i++) { - assertEquals(msg(i), 0xff & copy[i], readHandle.read()); - } - } + checkWriteEndianes(readHandleSupplier, writeHandleSupplier, + ByteOrder.LITTLE_ENDIAN); + checkWriteEndianes(readHandleSupplier, writeHandleSupplier, + ByteOrder.LITTLE_ENDIAN); + checkAdvancedStringWriting(readHandleSupplier, writeHandleSupplier); } } diff --git a/src/test/java/org/scijava/io/location/BytesLocationTest.java b/src/test/java/org/scijava/io/location/BytesLocationTest.java index f95144ca3..4dbcd46a4 100644 --- a/src/test/java/org/scijava/io/location/BytesLocationTest.java +++ b/src/test/java/org/scijava/io/location/BytesLocationTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,10 +33,12 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; +import org.scijava.io.ByteArrayByteBank; +import org.scijava.util.ByteArray; /** * Tests {@link BytesLocation}. - * + * * @author Curtis Rueden */ public class BytesLocationTest { @@ -72,4 +71,31 @@ public void testBytesOffsetLength() { assertArrayEquals(expectedDigits, testDigits); } + /** + * Tests getName() + */ + @Test + public void getNameTest() { + + final BytesLocation loc1 = new BytesLocation(0); + assertEquals(loc1.defaultName(), loc1.getName()); + assertEquals("Location.defaultName", loc1.defaultName()); + + final String expectedName = "test.name"; + BytesLocation loc2 = new BytesLocation(0, expectedName); + assertEquals(expectedName, loc2.getName()); + + loc2 = new BytesLocation(new byte[0], expectedName); + assertEquals(expectedName, loc2.getName()); + + loc2 = new BytesLocation(new ByteArray(), expectedName); + assertEquals(expectedName, loc2.getName()); + + loc2 = new BytesLocation(new ByteArrayByteBank(), expectedName); + assertEquals(expectedName, loc2.getName()); + + loc2 = new BytesLocation(new byte[0], 0, 0, expectedName); + assertEquals(expectedName, loc2.getName()); + } + } diff --git a/src/test/java/org/scijava/io/location/FileLocationResolverTest.java b/src/test/java/org/scijava/io/location/FileLocationResolverTest.java index 9e94b0281..0b71e739f 100644 --- a/src/test/java/org/scijava/io/location/FileLocationResolverTest.java +++ b/src/test/java/org/scijava/io/location/FileLocationResolverTest.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 diff --git a/src/test/java/org/scijava/io/location/FileLocationTest.java b/src/test/java/org/scijava/io/location/FileLocationTest.java index 43bc8b0f7..b9d189f0f 100644 --- a/src/test/java/org/scijava/io/location/FileLocationTest.java +++ b/src/test/java/org/scijava/io/location/FileLocationTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 5d6d5d9b7..5889dae32 100644 --- a/src/test/java/org/scijava/io/location/LocationServiceTest.java +++ b/src/test/java/org/scijava/io/location/LocationServiceTest.java @@ -2,20 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 @@ -33,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; @@ -46,6 +44,7 @@ * Tests {@link LocationService}. * * @author Gabriel Einsdorf + * @author Curtis Rueden */ public class LocationServiceTest { @@ -55,7 +54,7 @@ public void testResolve() throws URISyntaxException { final LocationService loc = ctx.getService(LocationService.class); final URI uri = new File(new File(".").getAbsolutePath()).toURI(); - final LocationResolver res = loc.getResolver(uri); + final LocationResolver res = loc.getHandler(uri); assertTrue(res instanceof FileLocationResolver); assertEquals(uri, res.resolve(uri).getURI()); @@ -63,4 +62,34 @@ 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); + final LocationService loc = ctx.getService(LocationService.class); + + final String uri = new File(".").getAbsolutePath(); + final Location res = loc.resolve(uri); + + assertTrue(res instanceof FileLocation); + FileLocation resFile = (FileLocation) res; + assertEquals(uri, resFile.getFile().getAbsolutePath()); + } + } diff --git a/src/test/java/org/scijava/io/location/URILocationTest.java b/src/test/java/org/scijava/io/location/URILocationTest.java index 5298b1d6a..49ff094ab 100644 --- a/src/test/java/org/scijava/io/location/URILocationTest.java +++ b/src/test/java/org/scijava/io/location/URILocationTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 1f74e1cb3..f053a1fab 100644 --- a/src/test/java/org/scijava/io/location/URLLocationTest.java +++ b/src/test/java/org/scijava/io/location/URLLocationTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 a1c571107..76fdf7e21 100644 --- a/src/test/java/org/scijava/io/nio/ByteBufferByteBankTest.java +++ b/src/test/java/org/scijava/io/nio/ByteBufferByteBankTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 b9be5999b..8817580ee 100644 --- a/src/test/java/org/scijava/log/CallingClassUtilsTest.java +++ b/src/test/java/org/scijava/log/CallingClassUtilsTest.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 @@ -33,6 +31,8 @@ import org.junit.Test; +import java.util.function.Supplier; + import static org.junit.Assert.assertEquals; /** @@ -43,26 +43,26 @@ public class CallingClassUtilsTest { @Test public void testGetCallingClass() { - Class callingClass = CallingClassUtils.getCallingClass(); - assertEquals(this.getClass(), callingClass); + String callingClass = CallingClassUtils.getCallingClassName(); + assertEquals(this.getClass().getName(), callingClass); } @Test public void testIgnoreAsCallingClass() { - assertEquals(ClassA.class, ClassA.returnGetCallingClass()); - assertEquals(this.getClass(), ClassB.returnGetCallingClass()); + assertEquals(ClassA.class.getName(), ClassA.returnGetCallingClass()); + assertEquals(this.getClass().getName(), ClassB.returnGetCallingClass()); } public static class ClassA { - static Class returnGetCallingClass() { - return CallingClassUtils.getCallingClass(); + static String returnGetCallingClass() { + return CallingClassUtils.getCallingClassName(); } } @IgnoreAsCallingClass private static class ClassB { - static Class returnGetCallingClass() { - return CallingClassUtils.getCallingClass(); + static String returnGetCallingClass() { + return CallingClassUtils.getCallingClassName(); } } } diff --git a/src/test/java/org/scijava/log/DefaultLoggerTest.java b/src/test/java/org/scijava/log/DefaultLoggerTest.java index 5abf54683..5c2f29805 100644 --- a/src/test/java/org/scijava/log/DefaultLoggerTest.java +++ b/src/test/java/org/scijava/log/DefaultLoggerTest.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 diff --git a/src/test/java/org/scijava/log/LogMessageTest.java b/src/test/java/org/scijava/log/LogMessageTest.java index 0f19c0b65..0699ddc37 100644 --- a/src/test/java/org/scijava/log/LogMessageTest.java +++ b/src/test/java/org/scijava/log/LogMessageTest.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 diff --git a/src/test/java/org/scijava/log/LogServiceTest.java b/src/test/java/org/scijava/log/LogServiceTest.java index a3c510d3a..78a128073 100644 --- a/src/test/java/org/scijava/log/LogServiceTest.java +++ b/src/test/java/org/scijava/log/LogServiceTest.java @@ -1,3 +1,31 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.log; import org.junit.Test; diff --git a/src/test/java/org/scijava/log/LogSourceTest.java b/src/test/java/org/scijava/log/LogSourceTest.java index b83c7d9ab..e6d7883a7 100644 --- a/src/test/java/org/scijava/log/LogSourceTest.java +++ b/src/test/java/org/scijava/log/LogSourceTest.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 @@ -115,4 +113,4 @@ public void testSetLogLevel() { assertTrue(source.hasLogLevel()); assertEquals(LogLevel.INFO, source.logLevel()); } -} \ No newline at end of file +} diff --git a/src/test/java/org/scijava/log/StderrLogServiceTest.java b/src/test/java/org/scijava/log/StderrLogServiceTest.java index bf740226e..42db64727 100644 --- a/src/test/java/org/scijava/log/StderrLogServiceTest.java +++ b/src/test/java/org/scijava/log/StderrLogServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 fbc31946c..94ed38813 100644 --- a/src/test/java/org/scijava/log/TestLogListener.java +++ b/src/test/java/org/scijava/log/TestLogListener.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 diff --git a/src/test/java/org/scijava/main/MainServiceTest.java b/src/test/java/org/scijava/main/MainServiceTest.java index 76d1fd854..e87501a7b 100644 --- a/src/test/java/org/scijava/main/MainServiceTest.java +++ b/src/test/java/org/scijava/main/MainServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 c361345df..20c0997fe 100644 --- a/src/test/java/org/scijava/main/run/MainCodeRunnerTest.java +++ b/src/test/java/org/scijava/main/run/MainCodeRunnerTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 f228f7d79..a3b2f203f 100644 --- a/src/test/java/org/scijava/menu/MenuServiceTest.java +++ b/src/test/java/org/scijava/menu/MenuServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 e0f06e0c3..5eb75a2cb 100644 --- a/src/test/java/org/scijava/menu/ShadowMenuTest.java +++ b/src/test/java/org/scijava/menu/ShadowMenuTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 08604b4e3..cdaf44a84 100644 --- a/src/test/java/org/scijava/module/ModuleServiceTest.java +++ b/src/test/java/org/scijava/module/ModuleServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,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; @@ -45,6 +46,7 @@ import org.junit.Before; import org.junit.Test; import org.scijava.Context; +import org.scijava.parse.ParseService; /** * Tests {@link ModuleService}. @@ -57,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); } @@ -161,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() { @@ -170,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..def867107 --- /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 - 2025 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 b3cbc60ca..7698f30b9 100644 --- a/src/test/java/org/scijava/module/process/LoggerPreprocessorTest.java +++ b/src/test/java/org/scijava/module/process/LoggerPreprocessorTest.java @@ -2,19 +2,17 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck - * Institute of Molecular Cell Biology and Genetics. + * Copyright (C) 2009 - 2025 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 diff --git a/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java b/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java index 8ad866534..719ed815f 100644 --- a/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java +++ b/src/test/java/org/scijava/module/run/ModuleCodeRunnerTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 new file mode 100644 index 000000000..7ceef8e27 --- /dev/null +++ b/src/test/java/org/scijava/object/NamedObjectIndexTest.java @@ -0,0 +1,71 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.object; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; + +public class NamedObjectIndexTest { + + @Test + public void testNamedObjects() { + NamedObjectIndex index = new NamedObjectIndex<>(String.class); + String obj1 = "obj1"; + String name1 = "name1"; + String obj2 = "obj1"; + String name2 = "name1"; + assertTrue(index.add(obj1, name1)); + assertTrue(index.add(obj2, String.class, name2, false)); + assertTrue(index.contains(obj1)); + assertTrue(index.contains(obj2)); + assertEquals(name1, index.getName(obj1)); + assertEquals(name2, index.getName(obj2)); + assertTrue(index.remove(obj1)); + assertTrue(index.remove(obj2)); + assertFalse(index.contains(obj1)); + assertFalse(index.contains(obj2)); + } + + @Test + public void testNullNames() { + NamedObjectIndex index = new NamedObjectIndex<>(String.class); + String obj1 = "object1"; + String name1 = null; + String obj2 = "object2"; + String name2 = ""; + assertTrue(index.add(obj1, name1)); + assertTrue(index.add(obj2, name2)); + assertEquals(name1, index.getName(obj1)); + assertEquals(name2, index.getName(obj2)); + } +} diff --git a/src/test/java/org/scijava/object/ObjectIndexTest.java b/src/test/java/org/scijava/object/ObjectIndexTest.java index 6e662eef4..95f0c9dc8 100644 --- a/src/test/java/org/scijava/object/ObjectIndexTest.java +++ b/src/test/java/org/scijava/object/ObjectIndexTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +36,7 @@ import static org.junit.Assert.assertTrue; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -212,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 new file mode 100644 index 000000000..c8f27051e --- /dev/null +++ b/src/test/java/org/scijava/object/ObjectServiceTest.java @@ -0,0 +1,103 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.object; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.plugin.PluginInfo; +import org.scijava.plugin.SciJavaPlugin; + +public class ObjectServiceTest { + + private Context context; + private ObjectService objectService; + + @Before + public void setUp() { + context = new Context(ObjectService.class); + objectService = context.getService(ObjectService.class); + } + + @After + public void tearDown() { + context.dispose(); + } + + @Test + public void testAddRemoveObjects() { + Object obj1 = new Object(); + String name1 = "Object 1"; + Object obj2 = ""; + Object obj3 = new Double(0.3); + PluginInfo obj4 = PluginInfo.create(TestPlugin.class, SciJavaPlugin.class); + obj4.setName("TestPlugin name"); + + objectService.addObject(obj1, name1); + assertEquals("Name of object 1", name1, objectService.getName(obj1)); + objectService.addObject(obj2); + assertEquals("Name of object 2", obj2.toString(), objectService.getName(obj2)); + objectService.addObject(obj3, null); + assertEquals("Name of object 3", obj3.toString(), objectService.getName(obj3)); + objectService.addObject(obj4); + assertNotNull(objectService.getName(obj4)); + assertEquals("Name of object 4", obj4.getName(), objectService.getName(obj4)); + + assertTrue("Object 1 registered", objectService.getObjects(Object.class).contains(obj1)); + assertTrue("Object 2 registered", objectService.getObjects(Object.class).contains(obj2)); + assertTrue("Object 3 registered", objectService.getObjects(Object.class).contains(obj3)); + assertTrue("Object 4 registered", objectService.getObjects(Object.class).contains(obj4)); + + objectService.removeObject(obj1); + objectService.removeObject(obj2); + objectService.removeObject(obj3); + objectService.removeObject(obj4); + + assertFalse("Object 1 removed", objectService.getObjects(Object.class).contains(obj1)); + assertFalse("Object 2 removed", objectService.getObjects(Object.class).contains(obj2)); + assertFalse("Object 3 removed", objectService.getObjects(Object.class).contains(obj3)); + assertFalse("Object 4 removed", objectService.getObjects(Object.class).contains(obj4)); + } + + @Test + public void testNamedObjectIndex() { + ObjectIndex index = objectService.getIndex(); + assertTrue(index instanceof NamedObjectIndex); + } + + private class TestPlugin implements SciJavaPlugin { + + } +} diff --git a/src/test/java/org/scijava/object/SortedObjectIndexTest.java b/src/test/java/org/scijava/object/SortedObjectIndexTest.java index 255780dc6..3a3c31e97 100644 --- a/src/test/java/org/scijava/object/SortedObjectIndexTest.java +++ b/src/test/java/org/scijava/object/SortedObjectIndexTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 7ac1e4dd9..da1b4a51a 100644 --- a/src/test/java/org/scijava/options/OptionsTest.java +++ b/src/test/java/org/scijava/options/OptionsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -97,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(); @@ -115,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 fd24e86ac..ffe1ee60d 100644 --- a/src/test/java/org/scijava/parse/ParseServiceTest.java +++ b/src/test/java/org/scijava/parse/ParseServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 cf3984c85..7c83b3b57 100644 --- a/src/test/java/org/scijava/plugin/PluginFinderTest.java +++ b/src/test/java/org/scijava/plugin/PluginFinderTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -46,33 +43,33 @@ public class PluginFinderTest { /** - * Tests that the {@code scijava.plugin.blacklist} system property works to + * Tests that the {@code scijava.plugin.blocklist} system property works to * exclude plugins from the index, even when they are on the classpath. */ @Test - public void testPluginBlacklistSystemProperty() { + public void testPluginBlocklistSystemProperty() { // check that the plugin is there, normally Context context = new Context(PluginService.class); PluginService pluginService = context.service(PluginService.class); PluginInfo plugin = // - pluginService.getPlugin(BlacklistedPlugin.class); - assertSame(BlacklistedPlugin.class.getName(), plugin.getClassName()); + pluginService.getPlugin(BlocklistedPlugin.class); + assertSame(BlocklistedPlugin.class.getName(), plugin.getClassName()); context.dispose(); - // blacklist the plugin, then check that it is absent - System.setProperty("scijava.plugin.blacklist", ".*BlacklistedPlugin"); + // blocklist the plugin, then check that it is absent + System.setProperty("scijava.plugin.blocklist", ".*BlocklistedPlugin"); context = new Context(PluginService.class); pluginService = context.service(PluginService.class); - plugin = pluginService.getPlugin(BlacklistedPlugin.class); + plugin = pluginService.getPlugin(BlocklistedPlugin.class); assertNull(plugin); context.dispose(); // reset the system - System.getProperties().remove("scijava.plugin.blacklist"); + System.getProperties().remove("scijava.plugin.blocklist"); } @Plugin(type = SciJavaPlugin.class) - public static class BlacklistedPlugin implements SciJavaPlugin { + public static class BlocklistedPlugin implements SciJavaPlugin { // NB: No implementation needed. } diff --git a/src/test/java/org/scijava/plugin/PluginIndexTest.java b/src/test/java/org/scijava/plugin/PluginIndexTest.java index 59e881152..76a076493 100644 --- a/src/test/java/org/scijava/plugin/PluginIndexTest.java +++ b/src/test/java/org/scijava/plugin/PluginIndexTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 20c0b5ebb..ae9098a0d 100644 --- a/src/test/java/org/scijava/plugin/PluginInfoTest.java +++ b/src/test/java/org/scijava/plugin/PluginInfoTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,10 +30,16 @@ package org.scijava.plugin; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; import java.util.List; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.scijava.Context; import org.scijava.InstantiableException; @@ -49,11 +52,24 @@ */ public class PluginInfoTest { + private Context context; + private PluginIndex pluginIndex; + + @Before + public void setUp() { + context = new Context(true); + pluginIndex = context.getPluginIndex(); + } + + @After + public void tearDown() { + context.dispose(); + context = null; + pluginIndex = null; + } + @Test public void testNames() throws InstantiableException { - final Context context = new Context(true); - final PluginIndex pluginIndex = context.getPluginIndex(); - final List> infos = pluginIndex.get(IceCream.class); assertEquals(3, infos.size()); @@ -62,9 +78,74 @@ public void testNames() throws InstantiableException { assertPlugin(Flavorless.class, IceCream.class, "", infos.get(2)); } + @Test + public void testGet() throws InstantiableException { + final PluginInfo chocolateInfo = // + PluginInfo.get(Chocolate.class, pluginIndex); + assertPlugin(Chocolate.class, IceCream.class, "chocolate", chocolateInfo); + + final PluginInfo chocolateInfoWithType = // + PluginInfo.get(Chocolate.class, IceCream.class, pluginIndex); + assertSame(chocolateInfo, chocolateInfoWithType); + + class Sherbet implements IceCream {} + assertNull(PluginInfo.get(Sherbet.class, pluginIndex)); + } + + @Test + public void testCreate() throws InstantiableException { + final PluginInfo chocolateInfo = PluginInfo.create(Chocolate.class); + assertPlugin(Chocolate.class, IceCream.class, "chocolate", chocolateInfo); + + final PluginInfo chocolateInfoWithType = // + PluginInfo.create(Chocolate.class, IceCream.class); + assertPlugin(Chocolate.class, IceCream.class, "chocolate", + chocolateInfoWithType); + assertNotSame(chocolateInfo, chocolateInfoWithType); + + class Sherbet implements IceCream {} + final PluginInfo sherbetInfoWithType = // + PluginInfo.create(Sherbet.class, IceCream.class); + assertPlugin(Sherbet.class, IceCream.class, null, sherbetInfoWithType); + + try { + final PluginInfo result = PluginInfo.create(Sherbet.class); + fail("Expected IllegalArgumentException but got: " + result); + } + catch (final IllegalArgumentException exc) { + // NB: Expected. + } + } + + @Test + public void testGetOrCreate() throws InstantiableException { + final PluginInfo chocolateInfo = // + PluginInfo.getOrCreate(Chocolate.class, pluginIndex); + assertPlugin(Chocolate.class, IceCream.class, "chocolate", chocolateInfo); + + final PluginInfo chocolateInfoWithType = // + PluginInfo.getOrCreate(Chocolate.class, IceCream.class, pluginIndex); + assertSame(chocolateInfo, chocolateInfoWithType); + + class Sherbet implements IceCream {} + final PluginInfo sherbetInfoWithType = // + PluginInfo.getOrCreate(Sherbet.class, IceCream.class, pluginIndex); + assertPlugin(Sherbet.class, IceCream.class, null, sherbetInfoWithType); + + try { + final PluginInfo result = // + PluginInfo.getOrCreate(Sherbet.class, pluginIndex); + fail("Expected IllegalArgumentException but got: " + result); + } + catch (final IllegalArgumentException exc) { + // NB: Expected. + } + } + private void assertPlugin(Class pluginClass, Class pluginType, String name, PluginInfo info) throws InstantiableException { + assertNotNull(info); assertSame(pluginClass, info.loadClass()); assertSame(pluginType, info.getPluginType()); assertEquals(name, info.getName()); diff --git a/src/test/java/org/scijava/plugin/SingletonServiceTest.java b/src/test/java/org/scijava/plugin/SingletonServiceTest.java new file mode 100644 index 000000000..1ef3e82de --- /dev/null +++ b/src/test/java/org/scijava/plugin/SingletonServiceTest.java @@ -0,0 +1,286 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.plugin; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.convert.AbstractConverter; +import org.scijava.convert.ConvertService; +import org.scijava.convert.Converter; +import org.scijava.plugin.event.PluginsAddedEvent; +import org.scijava.plugin.event.PluginsRemovedEvent; + +/** + * Tests for the {@link SingletonService} + * + * @author Gabriel Einsdorf KNIME GmbH + * @author Stefan Helfrich KNIME GmbH + */ +public class SingletonServiceTest { + + private PluginService pluginService; + private ConvertService convertService; + + @Before + public void setUp() { + final Context context = new Context(PluginService.class, + ConvertService.class); + pluginService = context.service(PluginService.class); + convertService = context.service(ConvertService.class); + } + + @After + public void tearDown() { + pluginService.context().dispose(); + } + + /** + * Tests that the {@link AbstractSingletonService} properly handles + * {@link PluginsAddedEvent}s originating from the {@link PluginService}. + */ + @Test + public void testSingletonServicePluginsAddedHandling() { + @SuppressWarnings("rawtypes") + final PluginInfo converterInfo = new PluginInfo<>( + FoodConverter.class, Converter.class); + + pluginService.addPlugin(converterInfo); + + assertNotNull(pluginService.getPlugin(FoodConverter.class)); + assertTrue(convertService.supports(new Apple() {}, Peach.class)); + } + + /** + * Tests that the {@link AbstractSingletonService} properly handles + * {@link PluginsAddedEvent}s that replace an instance. + */ + @Test + public void testSingletonServicePluginsAddedHandlingDuplicates() { + @SuppressWarnings("rawtypes") + final PluginInfo converterInfo = new PluginInfo<>( + FoodConverter.class, Converter.class); + + pluginService.addPlugin(converterInfo); + final FoodConverter firstInstance = convertService.getInstance( + FoodConverter.class); + + pluginService.addPlugin(converterInfo); + final FoodConverter secondInstance = convertService.getInstance( + FoodConverter.class); + + assertNotSame(firstInstance, secondInstance); + assertTrue(convertService.supports(new Apple() {}, Peach.class)); + } + + /** + * Tests that the {@link AbstractSingletonService} properly handles + * {@link PluginsRemovedEvent}s originating from the {@link PluginService}. + */ + @Test + public void testSingletonServiceManuallyAddedPluginsRemovedHandling() { + @SuppressWarnings("rawtypes") + final PluginInfo converterInfo = new PluginInfo<>( + FoodConverter.class, Converter.class); + + pluginService.addPlugin(converterInfo); + + // De-register DummyStringConverter + pluginService.removePlugin(converterInfo); + + assertNull(pluginService.getPlugin(FoodConverter.class)); + assertFalse(convertService.supports(new Apple() {}, Peach.class)); + } + + /** + * Tests that the {@link AbstractSingletonService} properly handles + * {@link PluginsRemovedEvent}s originating from the {@link PluginService}. + */ + @Test + public void testSingletonServiceCompileTimePluginsRemovedHandling() { + final PluginInfo pluginInfo = pluginService.getPlugin( + DiscoveredFoodConverter.class); + + // De-register DiscoveredFoodConverter + pluginService.removePlugin(pluginInfo); + + assertNull(pluginService.getPlugin(DiscoveredFoodConverter.class)); + assertFalse(convertService.supports(new Orange() {}, Peach.class)); + } + + /** + * Dummy {@link Converter}. + */ + public static class FoodConverter extends AbstractConverter { + + @Override + public T convert(final Object src, final Class dest) { + return null; + } + + @Override + public Class getOutputType() { + return Peach.class; + } + + @Override + public Class getInputType() { + return Apple.class; + } + } + + /** + * Dummy {@link Converter} that is added automatically. + */ + @Plugin(type = Converter.class) + public static class DiscoveredFoodConverter extends + AbstractConverter + { + + @Override + public T convert(final Object src, final Class dest) { + return null; + } + + @Override + public Class getOutputType() { + return Peach.class; + } + + @Override + public Class getInputType() { + return Orange.class; + } + } + + /** + * Type interface for conversion + */ + public interface Apple { + // NB + } + + /** + * Type interface for conversion + */ + public interface Orange { + // NB + } + + /** + * Type interface for conversion + */ + public interface Peach { + // NB + } + + /** + * Tests that plugins are added to and removed from the correct singleton + * service + */ + @Test + public void testListenToRemove() { + + final Context ctx = new Context(PluginService.class, + DummySingletonService.class, DummySingletonService2.class); + + final DummySingletonService dss = ctx.getService( + DummySingletonService.class); + + final DummySingletonService2 dss2 = ctx.getService( + DummySingletonService2.class); + + final List instances = dss.getInstances(); + final DummyPlugin dummy = instances.get(0); + + assertFalse("Service not correctly initialized", dss2.getInstances() + .isEmpty()); + + // test successful removal + final PluginService ps = ctx.getService(PluginService.class); + ps.removePlugin(dummy.getInfo()); + + assertFalse("Plugin was removed from wrong service!", dss2.getInstances() + .isEmpty()); + assertTrue("Plugin was not removed!", dss.getInstances().isEmpty()); + + // test successful add + ps.addPlugin(dummy.getInfo()); + assertEquals("Wrong number of plugins in service:", 1, dss.getInstances() + .size()); + assertEquals("Wrong number of plugins in independent service:", 1, dss2 + .getInstances().size()); + } + + @Plugin(type = DummyPlugin.class) + public static class DummyPlugin extends AbstractRichPlugin implements + SingletonPlugin + { + // NB: No implementation needed. + } + + public static class DummySingletonService extends + AbstractSingletonService + { + + @Override + public Class getPluginType() { + return DummyPlugin.class; + } + } + + @Plugin(type = DummyPlugin2.class) + public static class DummyPlugin2 extends AbstractRichPlugin implements + SingletonPlugin + { + // NB: No implementation needed. + } + + public static class DummySingletonService2 extends + AbstractSingletonService + { + + @Override + public Class getPluginType() { + return DummyPlugin2.class; + } + } + +} diff --git a/src/test/java/org/scijava/prefs/PrefServiceTest.java b/src/test/java/org/scijava/prefs/PrefServiceTest.java index b768d960b..7a8535ed0 100644 --- a/src/test/java/org/scijava/prefs/PrefServiceTest.java +++ b/src/test/java/org/scijava/prefs/PrefServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 17a38ab2d..71e2213d9 100644 --- a/src/test/java/org/scijava/run/RunServiceTest.java +++ b/src/test/java/org/scijava/run/RunServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 b9117d27c..8ad3ef941 100644 --- a/src/test/java/org/scijava/script/AbstractScriptLanguageTest.java +++ b/src/test/java/org/scijava/script/AbstractScriptLanguageTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 8c72c5f8f..f8fac4dc9 100644 --- a/src/test/java/org/scijava/script/ScriptEngineTest.java +++ b/src/test/java/org/scijava/script/ScriptEngineTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 d47d2d858..74fdc4583 100644 --- a/src/test/java/org/scijava/script/ScriptFinderTest.java +++ b/src/test/java/org/scijava/script/ScriptFinderTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -69,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", // @@ -111,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", // @@ -142,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", // @@ -180,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 521327ccf..eb53d3d2d 100644 --- a/src/test/java/org/scijava/script/ScriptInfoTest.java +++ b/src/test/java/org/scijava/script/ScriptInfoTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -68,6 +65,7 @@ import org.scijava.test.TestUtils; import org.scijava.util.DigestUtils; import org.scijava.util.FileUtils; +import org.scijava.widget.WidgetStyle; /** * Tests {@link ScriptInfo}. @@ -252,13 +250,14 @@ public void testVersion() throws IOException { @Test public void testParameters() { final String script = "" + // - "% @LogService(required = false) log\n" + // - "% @int(label=\"Slider Value\", softMin=5, softMax=15, " + // - "stepSize=3, value=11, style=\"slider\") sliderValue\n" + // - "% @String(persist = false, family='Carnivora', " + // + "#@ LogService (required = false) log\n" + // + "#@ int (label=\"Slider Value\", softMin=5, softMax=15, " + // + "stepSize=3, value=11, style=\" slidEr,\") sliderValue\n" + // + "#@ String (persist = false, family='Carnivora', " + // "choices={'quick brown fox', 'lazy dog'}) animal\n" + // - "% @String(visibility=MESSAGE) msg\n" + // - "% @BOTH java.lang.StringBuilder buffer"; + "#@ Double (autoFill = false) notAutoFilled\n" + // + "#@ String (visibility=MESSAGE) msg\n" + // + "#@BOTH java.lang.StringBuilder buffer"; final ScriptInfo info = new ScriptInfo(context, "params.bsizes", new StringReader(script)); @@ -271,7 +270,8 @@ public void testParameters() { final ModuleItem sliderValue = info.getInput("sliderValue"); assertItem("sliderValue", int.class, "Slider Value", ItemIO.INPUT, true, - true, null, "slider", 11, null, null, 5, 15, 3.0, noChoices, sliderValue); + true, null, " slidEr,", 11, null, null, 5, 15, 3.0, noChoices, sliderValue); + assertTrue("Case-insensitive trimmed style", WidgetStyle.isStyle(sliderValue, "slider")); final ModuleItem animal = info.getInput("animal"); final List animalChoices = // @@ -280,6 +280,9 @@ public void testParameters() { null, null, null, null, null, null, null, null, animalChoices, animal); assertEquals(animal.get("family"), "Carnivora"); // test custom attribute + final ModuleItem notAutoFilled = info.getInput("notAutoFilled"); + assertFalse(notAutoFilled.isAutoFill()); + final ModuleItem msg = info.getInput("msg"); assertSame(ItemVisibility.MESSAGE, msg.getVisibility()); @@ -288,7 +291,7 @@ public void testParameters() { null, null, null, null, null, null, null, null, noChoices, buffer); int inputCount = 0; - final ModuleItem[] inputs = { log, sliderValue, animal, msg, buffer }; + final ModuleItem[] inputs = { log, sliderValue, animal, notAutoFilled, msg, buffer }; for (final ModuleItem inItem : info.inputs()) { assertSame(inputs[inputCount++], inItem); } @@ -404,7 +407,7 @@ public List getExtensions() { } } - // -- Test script langauge -- + // -- Test script language -- private static class BindingSizesEngine extends AbstractScriptEngine { diff --git a/src/test/java/org/scijava/script/ScriptServiceTest.java b/src/test/java/org/scijava/script/ScriptServiceTest.java index 01782d057..404550f5d 100644 --- a/src/test/java/org/scijava/script/ScriptServiceTest.java +++ b/src/test/java/org/scijava/script/ScriptServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -129,5 +126,4 @@ public void testArrayAliases() throws ScriptException { ctx.dispose(); } - } diff --git a/src/test/java/org/scijava/script/process/ParameterScriptProcessorTest.java b/src/test/java/org/scijava/script/process/ParameterScriptProcessorTest.java new file mode 100644 index 000000000..8e9c5b653 --- /dev/null +++ b/src/test/java/org/scijava/script/process/ParameterScriptProcessorTest.java @@ -0,0 +1,82 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.process; + +import static org.junit.Assert.*; + +import java.io.StringReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.script.ScriptInfo; + +public class ParameterScriptProcessorTest { + + private Context context; + + @Before + public void setUp() { + context = new Context(); + } + + @After + public void tearDown() { + context.dispose(); + } + + @Test + public void testScriptParameterParsing() { + String script = "" + // + "% @String legacyStyleParameter\n" + + "% #@ String commentedHeaderParameter\n" + + "% ############## Some Comment ###########\n" + + "#@ String implicitInputParameter\n" + + "#@input String explicitInputParameter\n" + + "\n" + + "% @String legacyStyleBodyParameter\n" + + "% #@ String commentedBodyParameter\n" + + "\n" + + "#@output implicitlyTypedOutputParameter\n" + + "#@output String explicitlyTypedOutputParameter\n"; + final ScriptInfo info = new ScriptInfo(context, ".bsizes", new StringReader(script)); + assertEquals("legacyStyleParameter", info.getInput("legacyStyleParameter").getName()); + assertEquals("implicitInputParameter", info.getInput("implicitInputParameter").getName()); + assertEquals("explicitInputParameter", info.getInput("explicitInputParameter").getName()); + + assertEquals("implicitlyTypedOutputParameter", info.getOutput("implicitlyTypedOutputParameter").getName()); + assertEquals("explicitlyTypedOutputParameter", info.getOutput("explicitlyTypedOutputParameter").getName()); + + assertNull(info.getInput("commentedHeaderParameter")); + assertNull(info.getInput("legacyStyleBodyParameter")); + assertNull(info.getInput("commentedBodyParameter")); + } + +} diff --git a/src/test/java/org/scijava/service/ServiceIndexTest.java b/src/test/java/org/scijava/service/ServiceIndexTest.java index 4712282c0..ea3f6cc8c 100644 --- a/src/test/java/org/scijava/service/ServiceIndexTest.java +++ b/src/test/java/org/scijava/service/ServiceIndexTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 new file mode 100644 index 000000000..82d98f85f --- /dev/null +++ b/src/test/java/org/scijava/task/TaskEventTest.java @@ -0,0 +1,139 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.task; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.scijava.Context; +import org.scijava.event.EventHandler; +import org.scijava.task.event.TaskEvent; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * Tests whether many tasks run in parallel consistently trigger an Event + * when each task is started and when each task is ended. + * + * The test fails inconsistently, sometimes with a few tasks remaining, sometimes with almost all tasks remaining. + */ + +public class TaskEventTest { + + private TaskService taskService; + private TaskEventListener eventListener; + + static int nTasks = 500; // Putting higher value can lead to issues because too many threads cannot be launched in parallel + + @Before + public void setUp() { + final Context ctx = new Context(TaskService.class); + taskService = ctx.service(TaskService.class); + eventListener = new TaskEventListener(); + ctx.inject(eventListener); + } + + @After + public void tearDown() { + taskService.context().dispose(); + } + + @Test + public void testManyTasks() throws InterruptedException { + for (int i=0;i { + try { + Thread.sleep(msBeforeStart); + + // Task started + task.setProgressMaximum(100); + + task.run(() -> { + int totalMs = 0; + while(totalMs tasks = new HashSet<>(); + + @EventHandler + private synchronized void onEvent(final TaskEvent evt) { + Task task = evt.getTask(); + if (task.isDone()) { + tasks.remove(task); + } else { + tasks.add(task); + } + } + + public synchronized Set getLeftOvers() { + return new HashSet<>(tasks); + } + } +} diff --git a/src/test/java/org/scijava/task/TaskServiceTest.java b/src/test/java/org/scijava/task/TaskServiceTest.java index e9eb0e068..00b320b0a 100644 --- a/src/test/java/org/scijava/task/TaskServiceTest.java +++ b/src/test/java/org/scijava/task/TaskServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. * #L% */ + package org.scijava.task; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/scijava/test/AbstractSciJavaTest.java b/src/test/java/org/scijava/test/AbstractSciJavaTest.java index 3bf06dde2..3b859e001 100644 --- a/src/test/java/org/scijava/test/AbstractSciJavaTest.java +++ b/src/test/java/org/scijava/test/AbstractSciJavaTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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/test/TestUtilsTest.java b/src/test/java/org/scijava/test/TestUtilsTest.java index 181e3246b..69beb2bd2 100644 --- a/src/test/java/org/scijava/test/TestUtilsTest.java +++ b/src/test/java/org/scijava/test/TestUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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/text/TextServiceTest.java b/src/test/java/org/scijava/text/TextServiceTest.java new file mode 100644 index 000000000..fd16a40f3 --- /dev/null +++ b/src/test/java/org/scijava/text/TextServiceTest.java @@ -0,0 +1,86 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.text; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.io.File; +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.plugin.Plugin; + +/** Tests {@link TextService}. */ +public class TextServiceTest { + + private Context ctx; + private TextService textService; + + @Before + public void setUp() { + ctx = new Context(TextService.class); + textService = ctx.service(TextService.class); + } + + @After + public void tearDown() { + ctx.dispose(); + } + + @Test + public void testGetHandler() { + final TextFormat fooHandler = textService.getHandler(new File("data.foo")); + assertNotNull(fooHandler); + assertEquals(FooTextFormat.class, fooHandler.getClass()); + System.out.println(fooHandler); + + final TextFormat barHandler = textService.getHandler(new File("data.bar")); + assertNull(barHandler); + } + + @Plugin(type = TextFormat.class) + public static class FooTextFormat extends AbstractTextFormat { + + @Override + public List 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 576c5a9a5..29ce7b4dd 100644 --- a/src/test/java/org/scijava/thread/ThreadServiceTest.java +++ b/src/test/java/org/scijava/thread/ThreadServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 b54dfa540..9aba1641c 100644 --- a/src/test/java/org/scijava/ui/UIServiceTest.java +++ b/src/test/java/org/scijava/ui/UIServiceTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,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; @@ -82,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 2b2da010a..a67e4b758 100644 --- a/src/test/java/org/scijava/util/AppUtilsTest.java +++ b/src/test/java/org/scijava/util/AppUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 7521d018c..2ce778bb9 100644 --- a/src/test/java/org/scijava/util/ArrayUtilsTest.java +++ b/src/test/java/org/scijava/util/ArrayUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 f94955de0..9b8239e68 100644 --- a/src/test/java/org/scijava/util/BoolArrayTest.java +++ b/src/test/java/org/scijava/util/BoolArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 266bf2e01..0e8108951 100644 --- a/src/test/java/org/scijava/util/ByteArrayTest.java +++ b/src/test/java/org/scijava/util/ByteArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 4983e6461..9d4403e75 100644 --- a/src/test/java/org/scijava/util/CharArrayTest.java +++ b/src/test/java/org/scijava/util/CharArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 283ff45cd..1e3f809d4 100644 --- a/src/test/java/org/scijava/util/ClassUtilsTest.java +++ b/src/test/java/org/scijava/util/ClassUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 423a6d281..8f5225b58 100644 --- a/src/test/java/org/scijava/util/ColorRGBTest.java +++ b/src/test/java/org/scijava/util/ColorRGBTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 69e08bc91..f19b7f8e4 100644 --- a/src/test/java/org/scijava/util/ConversionUtilsTest.java +++ b/src/test/java/org/scijava/util/ConversionUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +43,6 @@ import java.util.Set; import org.junit.Test; -import org.scijava.util.Types; /** * Tests {@link ConversionUtils}. @@ -181,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)); } /** @@ -240,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); } /** @@ -257,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 4d0a837ff..c9b37378b 100644 --- a/src/test/java/org/scijava/util/DigestUtilsTest.java +++ b/src/test/java/org/scijava/util/DigestUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,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 }; @@ -56,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 @@ -78,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))); @@ -95,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))); @@ -121,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); @@ -158,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)}. */ @@ -172,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)}. */ @@ -185,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 e90c6d053..385b8ee31 100644 --- a/src/test/java/org/scijava/util/DoubleArrayTest.java +++ b/src/test/java/org/scijava/util/DoubleArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 e241854fb..0bbc6645e 100644 --- a/src/test/java/org/scijava/util/FileUtilsTest.java +++ b/src/test/java/org/scijava/util/FileUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 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 +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 @@ -180,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 @@ -312,6 +309,12 @@ public void testStripVersionFromFilename() { assertEquals("jars/jogl-all-natives-solaris-i586.jar", FileUtils.stripFilenameVersion("jars/jogl-all-2.3.0-natives-solaris-i586.jar")); assertEquals("jars/jogl-all-natives-windows-amd64.jar", FileUtils.stripFilenameVersion("jars/jogl-all-2.3.0-natives-windows-amd64.jar")); assertEquals("jars/jogl-all-natives-windows-i586.jar", FileUtils.stripFilenameVersion("jars/jogl-all-2.3.0-natives-windows-i586.jar")); + + // Test jinput style of native binary .jars + assertEquals("jars/jinput-natives-all.jar", FileUtils.stripFilenameVersion("jars/jinput-2.0.9-natives-all.jar")); + + // Test that native-lib-loader is not misrecognized as a native classifier + assertEquals("jars/native-lib-loader.jar", FileUtils.stripFilenameVersion("jars/native-lib-loader-2.3.2.jar")); } @Test diff --git a/src/test/java/org/scijava/util/FloatArrayTest.java b/src/test/java/org/scijava/util/FloatArrayTest.java index 356df3e18..9a8516ac9 100644 --- a/src/test/java/org/scijava/util/FloatArrayTest.java +++ b/src/test/java/org/scijava/util/FloatArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 new file mode 100644 index 000000000..5c6e06e9d --- /dev/null +++ b/src/test/java/org/scijava/util/GenericArrayTypesTest.java @@ -0,0 +1,78 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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 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.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Type; +import java.util.List; + +import org.junit.Test; + +public class GenericArrayTypesTest { + + @Test + public void testArrayFields() throws NoSuchFieldException, SecurityException { + Field rawField = Types.field(ClassWithFields.class, "rawListArray"); + Field genericWildcardField = Types.field(ClassWithFields.class, "wildcardListArray"); + Field genericTypedField = Types.field(ClassWithFields.class, "integerListArray"); + + Type rawFieldType = Types.fieldType(rawField, ClassWithFields.class); + Type genericWildcardFieldType = Types.fieldType(genericWildcardField, ClassWithFields.class); + Type genericTypedFieldType = Types.fieldType(genericTypedField, ClassWithFields.class); + + // raw type + assertFalse(rawFieldType instanceof GenericArrayType); + assertTrue(rawFieldType instanceof Class); + + // generic array types + assertTrue(genericWildcardFieldType instanceof GenericArrayType); + assertTrue(genericTypedFieldType instanceof GenericArrayType); + + assertEquals(rawField.getGenericType(), rawFieldType); + assertEquals(genericWildcardField.getGenericType(), genericWildcardFieldType); + assertEquals(genericTypedField.getGenericType(), genericTypedFieldType); + + assertSame(List[].class, Types.raw(rawFieldType)); + assertSame(List[].class, Types.raw(genericWildcardFieldType)); + assertSame(List[].class, Types.raw(genericTypedFieldType)); + } + + @SuppressWarnings({ "rawtypes", "unused" }) + private static class ClassWithFields { + public List[] rawListArray; + public List[] wildcardListArray; + public List[] integerListArray; + } +} diff --git a/src/test/java/org/scijava/util/IntArrayTest.java b/src/test/java/org/scijava/util/IntArrayTest.java index 4f22647b5..b28b46390 100644 --- a/src/test/java/org/scijava/util/IntArrayTest.java +++ b/src/test/java/org/scijava/util/IntArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 fd80647e2..10d11e427 100644 --- a/src/test/java/org/scijava/util/LastRecentlyUsedTest.java +++ b/src/test/java/org/scijava/util/LastRecentlyUsedTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 d1063a581..c0a384b7a 100644 --- a/src/test/java/org/scijava/util/LongArrayTest.java +++ b/src/test/java/org/scijava/util/LongArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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..28cef6cea --- /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 - 2025 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 40dc5bd61..8bcdf73ee 100644 --- a/src/test/java/org/scijava/util/ObjectArrayTest.java +++ b/src/test/java/org/scijava/util/ObjectArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 5ad61707e..2ca1ea072 100644 --- a/src/test/java/org/scijava/util/POMTest.java +++ b/src/test/java/org/scijava/util/POMTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -95,16 +92,16 @@ public void testAccessors() throws ParserConfigurationException, assertEquals("org.scijava", pom.getGroupId()); assertEquals("scijava-common", pom.getArtifactId()); assertNotNull(pom.getVersion()); - assertEquals("Travis CI", pom.getCIManagementSystem()); + assertEquals("GitHub Actions", pom.getCIManagementSystem()); final String ciManagementURL = pom.getCIManagementURL(); - assertEquals("https://travis-ci.org/scijava/scijava-common", + assertEquals("https://github.com/scijava/scijava-common/actions", ciManagementURL); assertEquals("GitHub Issues", pom.getIssueManagementSystem()); final String issueManagementURL = pom.getIssueManagementURL(); assertEquals("https://github.com/scijava/scijava-common/issues", issueManagementURL); assertEquals("SciJava", pom.getOrganizationName()); - assertEquals("http://www.scijava.org/", pom.getOrganizationURL()); + assertEquals("https://scijava.org/", pom.getOrganizationURL()); assertTrue(pom.getPath().endsWith("pom.xml")); assertTrue(pom.getProjectDescription().startsWith( "SciJava Common is a shared library for SciJava software.")); @@ -113,7 +110,7 @@ public void testAccessors() throws ParserConfigurationException, assertEquals("https://github.com/scijava/scijava-common", // pom.getProjectURL()); final String scmConnection = pom.getSCMConnection(); - assertEquals("scm:git:git://github.com/scijava/scijava-common", + assertEquals("scm:git:https://github.com/scijava/scijava-common", scmConnection); final String scmDeveloperConnection = pom.getSCMDeveloperConnection(); assertEquals("scm:git:git@github.com:scijava/scijava-common", diff --git a/src/test/java/org/scijava/util/PrimitiveArrayTest.java b/src/test/java/org/scijava/util/PrimitiveArrayTest.java index f4a5bfa72..64a74492b 100644 --- a/src/test/java/org/scijava/util/PrimitiveArrayTest.java +++ b/src/test/java/org/scijava/util/PrimitiveArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 e8882c123..ce3346a2c 100644 --- a/src/test/java/org/scijava/util/ProcessUtilsTest.java +++ b/src/test/java/org/scijava/util/ProcessUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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..3e3cc57fb --- /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 - 2025 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 5cd7b6cb2..005718285 100644 --- a/src/test/java/org/scijava/util/ShortArrayTest.java +++ b/src/test/java/org/scijava/util/ShortArrayTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 9559fd83c..95b0cd431 100644 --- a/src/test/java/org/scijava/util/StringUtilsTest.java +++ b/src/test/java/org/scijava/util/StringUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 597037454..d3529cb0c 100644 --- a/src/test/java/org/scijava/util/TypesTest.java +++ b/src/test/java/org/scijava/util/TypesTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -225,6 +222,7 @@ class Struct { private String[][] strings; private Void v; private List list; + private List[] listArray; private HashMap map; } assertSame(int[].class, raw(Struct.class, "intArray")); @@ -232,6 +230,7 @@ class Struct { assertSame(String[][].class, raw(Struct.class, "strings")); assertSame(Void.class, raw(Struct.class, "v")); assertSame(List.class, raw(Struct.class, "list")); + assertSame(List[].class, raw(Struct.class, "listArray")); assertSame(HashMap.class, raw(Struct.class, "map")); } @@ -310,6 +309,12 @@ public void testBox() { } } + /** Tests {@link Types#unbox(Class)}. */ + @Test + public void testUnbox() { + // TODO + } + /** Tests {@link Types#nullValue(Class)}. */ @Test public void testNullValue() { @@ -510,6 +515,31 @@ public void testIsAssignableClassToNull() { Types.isAssignable(Object.class, null); } + /** Tests {@link Types#isAssignable(Type, Type)} with type variable. */ + @Test + public void testIsAssignableT() { + final Type t = genericTestType("t"); + final Type listT = genericTestType("listT"); + final Type listNumber = genericTestType("listNumber"); + final Type listInteger = genericTestType("listInteger"); + final Type listExtendsNumber = genericTestType("listExtendsNumber"); + + assertTrue(Types.isAssignable(t, t)); + assertTrue(Types.isAssignable(listT, listT)); + assertTrue(Types.isAssignable(listNumber, listNumber)); + assertTrue(Types.isAssignable(listInteger, listInteger)); + assertTrue(Types.isAssignable(listExtendsNumber, listExtendsNumber)); + + assertTrue(Types.isAssignable(listT, listExtendsNumber)); + assertTrue(Types.isAssignable(listNumber, listExtendsNumber)); + assertTrue(Types.isAssignable(listInteger, listExtendsNumber)); + + assertFalse(Types.isAssignable(listNumber, listT)); + assertFalse(Types.isAssignable(listInteger, listT)); + assertFalse(Types.isAssignable(listExtendsNumber, listT)); + assertFalse(Types.isAssignable(listExtendsNumber, listNumber)); + } + /** Tests {@link Types#isInstance(Object, Class)}. */ @Test public void testIsInstance() { @@ -563,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. */ @@ -572,9 +602,60 @@ 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() { + // TODO + } + + /** Tests {@link Types#parameterize(Class, Type...)}. */ + @Test + public void testParameterizeTypes() { + // TODO + } + + /** Tests {@link Types#parameterizeWithOwner(Type, Class, Type...)}. */ + @Test + public void testParameterizeWithOwner() { + // TODO + } + // -- Helper classes -- private static class Thing { + @SuppressWarnings("unused") private T thing; } @@ -595,7 +676,26 @@ 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 { + T t(); + List listT(); + List listNumber(); + List listInteger(); + List listExtendsNumber(); } // -- Helper methods -- @@ -671,4 +771,7 @@ private void assertAllTheSame(final List list, final Object... values) { } } + private Type genericTestType(final String name) { + return Types.method(TestTypes.class, name).getGenericReturnType(); + } } diff --git a/src/test/java/org/scijava/util/UnitUtilsTest.java b/src/test/java/org/scijava/util/UnitUtilsTest.java index e0f060eca..e253a0319 100644 --- a/src/test/java/org/scijava/util/UnitUtilsTest.java +++ b/src/test/java/org/scijava/util/UnitUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution 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 e452ca1f1..f56be8426 100644 --- a/src/test/java/org/scijava/util/VersionUtilsTest.java +++ b/src/test/java/org/scijava/util/VersionUtilsTest.java @@ -2,10 +2,7 @@ * #%L * SciJava Common shared library for SciJava software. * %% - * Copyright (C) 2009 - 2017 Board of Regents of the University of - * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck - * Institute of Molecular Cell Biology and Genetics, University of - * Konstanz, and KNIME GmbH. + * Copyright (C) 2009 - 2025 SciJava developers. * %% * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -60,7 +57,7 @@ public void testCompare() { assertTrue(VersionUtils.compare("2.7.3", "1.7.3") > 0); // Suffix indicates version is older than final release. - assertTrue(VersionUtils.compare("1.5.2", "1.5.2-beta-1") < 0); + assertTrue(VersionUtils.compare("1.5.2", "1.5.2-beta-1") > 0); // Check when number of version tokens does not match. assertTrue(VersionUtils.compare("1.5", "1.5.1") < 0); @@ -88,6 +85,7 @@ public void testCompare() { // Check weird stuff. assertTrue(VersionUtils.compare("1", "a") < 0); + assertTrue(VersionUtils.compare("1", "%") > 0); assertTrue(VersionUtils.compare("", "1") < 0); assertTrue(VersionUtils.compare("1", "1.") < 0); assertTrue(VersionUtils.compare("", ".") < 0); diff --git a/src/test/java/org/scijava/widget/WidgetStyleTest.java b/src/test/java/org/scijava/widget/WidgetStyleTest.java new file mode 100644 index 000000000..0043dba69 --- /dev/null +++ b/src/test/java/org/scijava/widget/WidgetStyleTest.java @@ -0,0 +1,96 @@ +/*- + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2025 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.widget; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Enclosed.class) +public class WidgetStyleTest { + + @RunWith(Parameterized.class) + public static class TestIsStyle { + + static String[] styleStrings = { "foo, bar, someThing", " FOO, BAR, SOMEthing ", "foo ", " bar", + "trash, sOmEtHiNg", null }; + + static String[] stylesToTest = { "foo", "bar", "someThing", null }; + + static boolean[][] stylesToHave = { // foo, bar, someThing + new boolean[] { true, true, true, false }, new boolean[] { true, true, true, false }, + new boolean[] { true, false, false, false }, new boolean[] { false, true, false, false }, + new boolean[] { false, false, true, false }, new boolean[] { false, false, false, true } }; + + @Parameters(name = "{0}") + public static List params() { + return IntStream.range(0, styleStrings.length) + .mapToObj(i -> new Object[] { styleStrings[i], stylesToHave[i] }).collect(Collectors.toList()); + } + + @Parameter + public String styleString; + + @Parameter(1) + public boolean[] targetStyles; + + @Test + public void testSimpleStyles() { + for (int i = 0; i < stylesToTest.length; i++) { + assertEquals("style: " + stylesToTest[i], targetStyles[i], + WidgetStyle.isStyle(styleString, stylesToTest[i])); + } + } + } + + public static class TestStyleModifiers { + @Test + public void testStyleModifiers() { + String style = "open, extensions:tiff/tif/jpeg/jpg"; + Set extensions = new HashSet<>(Arrays.asList(WidgetStyle.getStyleModifiers(style, "extensions"))); + Set expected = new HashSet<>(Arrays.asList("tiff", "jpg", "jpeg", "tif")); + assertEquals(expected, extensions); + } + } +} diff --git a/src/test/resources/org/scijava/io/test.txt b/src/test/resources/org/scijava/io/test.txt new file mode 100644 index 000000000..d95f3ad14 --- /dev/null +++ b/src/test/resources/org/scijava/io/test.txt @@ -0,0 +1 @@ +content