diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/Connectivity.java b/Legacy/bonej/src/main/java/org/bonej/plugins/Connectivity.java index b499099d..12bce74d 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/Connectivity.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/Connectivity.java @@ -138,7 +138,6 @@ public void run(final String arg) { ri.setResultInRow(imp, "Connectivity", connectivity); ri.setResultInRow(imp, "Conn.D (" + imp.getCalibration().getUnit() + "^-3)", connDensity); ri.updateTable(); - UsageReporter.reportEvent(this).send(); return; } diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/DeleteSliceRange.java b/Legacy/bonej/src/main/java/org/bonej/plugins/DeleteSliceRange.java index 5247033e..d3caf299 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/DeleteSliceRange.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/DeleteSliceRange.java @@ -75,7 +75,6 @@ public void run(final String arg) { imp.setStack(null, stack); imp.show(); - UsageReporter.reportEvent(this).send(); } /** diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/DensityCalibrator.java b/Legacy/bonej/src/main/java/org/bonej/plugins/DensityCalibrator.java index 6a8a9d6c..f13178d3 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/DensityCalibrator.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/DensityCalibrator.java @@ -61,7 +61,6 @@ public void run(final String arg) { IJ.error("Can't calibrate image\n" + e.getMessage()); return; } - UsageReporter.reportEvent(this).send(); } private static void scanco(final ImagePlus imp) throws IllegalArgumentException { diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/Moments.java b/Legacy/bonej/src/main/java/org/bonej/plugins/Moments.java index 58e722d5..334821c5 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/Moments.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/Moments.java @@ -220,7 +220,6 @@ public void run(final String arg) { if (doAxes3D) show3DAxes(imp, E.getV(), centroid, startSlice, endSlice, min, max); - UsageReporter.reportEvent(this).send(); } /** diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/Orienteer.java b/Legacy/bonej/src/main/java/org/bonej/plugins/Orienteer.java index 90456fcc..ad04b3fb 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/Orienteer.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/Orienteer.java @@ -243,8 +243,6 @@ public Orienteer() { if (WindowManager.getImageCount() == 0) return; final ImagePlus imp = WindowManager.getCurrentImage(); setup(imp); - - UsageReporter.reportEvent(this).send(); } @Override diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/ParticleCounter.java b/Legacy/bonej/src/main/java/org/bonej/plugins/ParticleCounter.java index 1949a4b1..fb4ee510 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/ParticleCounter.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/ParticleCounter.java @@ -449,7 +449,6 @@ public void run(final String arg) { } IJ.showProgress(1.0); IJ.showStatus("Particle Analysis Complete"); - UsageReporter.reportEvent(this).send(); } /** diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/Purify.java b/Legacy/bonej/src/main/java/org/bonej/plugins/Purify.java index b95cf6a8..9d548f04 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/Purify.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/Purify.java @@ -99,7 +99,6 @@ public void run(final String arg) { if (showPerformance) { showResults(duration, imp); } - UsageReporter.reportEvent(this).send(); } diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/ReporterOptions.java b/Legacy/bonej/src/main/java/org/bonej/plugins/ReporterOptions.java deleted file mode 100644 index b02782cf..00000000 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/ReporterOptions.java +++ /dev/null @@ -1,83 +0,0 @@ -/*- - * #%L - * Mavenized version of the BoneJ1 plugins - * %% - * Copyright (C) 2015 - 2023 Michael Doube, BoneJ 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.bonej.plugins; - -import java.util.Random; - -import ij.Prefs; -import ij.gui.GenericDialog; -import ij.plugin.PlugIn; - -public class ReporterOptions implements PlugIn { - - static final String OPTOUTSET = "bonej.report.option.set"; - /** Set to false if reporting is not allowed */ - static final String OPTOUTKEY = "bonej.allow.reporter"; - static final String COOKIE = "bonej.report.cookie"; - static final String COOKIE2 = "bonej.report.cookie2"; - static final String FIRSTTIMEKEY = "bonej.report.firstvisit"; - static final String SESSIONKEY = "bonej.report.bonejsession"; - private static final String IJSESSIONKEY = "bonej.report.ijsession"; - - @Override - public void run(final String arg) { - - final GenericDialog dialog = new GenericDialog("BoneJ"); - dialog.addMessage("Allow usage data collection?"); - dialog.addMessage("BoneJ would like to collect data on \n" + - "which plugins are being used, to direct development\n" + - "and promote BoneJ to funders."); - dialog.addMessage("If you agree to participate please hit OK\n" + - "otherwise, cancel. For more information click Help."); - dialog.addHelp("https://imagej.github.io/plugins/bonej#usage-reporting"); - dialog.showDialog(); - if (dialog.wasCanceled()) { - Prefs.set(OPTOUTKEY, false); - Prefs.set(COOKIE, ""); - Prefs.set(COOKIE2, ""); - Prefs.set(FIRSTTIMEKEY, ""); - Prefs.set(SESSIONKEY, ""); - Prefs.set(IJSESSIONKEY, ""); - } - else { - Prefs.set(OPTOUTKEY, true); - Prefs.set(COOKIE, new Random().nextInt(Integer.MAX_VALUE)); - Prefs.set(COOKIE2, new Random().nextInt(Integer.MAX_VALUE)); - final long time = System.currentTimeMillis() / 1000; - Prefs.set(FIRSTTIMEKEY, Long.toString(time)); - Prefs.set(SESSIONKEY, 1); - } - - Prefs.set(OPTOUTSET, true); - Prefs.savePreferences(); - UsageReporter.reportEvent(this).send(); - } -} diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/SliceGeometry.java b/Legacy/bonej/src/main/java/org/bonej/plugins/SliceGeometry.java index d73073b0..4a60a7ca 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/SliceGeometry.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/SliceGeometry.java @@ -391,7 +391,6 @@ else if (roi.getType() != Roi.RECTANGLE) { if (do3DAnnotation) { show3DAxes(imp); } - UsageReporter.reportEvent(this).send(); } private void initOrientationCheckBox(final GenericDialog gd) { diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/SphereFitter.java b/Legacy/bonej/src/main/java/org/bonej/plugins/SphereFitter.java index b274b832..bfc7ae8d 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/SphereFitter.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/SphereFitter.java @@ -165,7 +165,6 @@ public void run(final String arg) { if (doRoiMan) { addToRoiManager(imp, roiMan, sphereDim, clearRois); } - UsageReporter.reportEvent(this).send(); } /** diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/UsageReporter.java b/Legacy/bonej/src/main/java/org/bonej/plugins/UsageReporter.java deleted file mode 100644 index e8da269f..00000000 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/UsageReporter.java +++ /dev/null @@ -1,268 +0,0 @@ -/*- - * #%L - * Mavenized version of the BoneJ1 plugins - * %% - * Copyright (C) 2015 - 2023 Michael Doube, BoneJ 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.bonej.plugins; - -import java.awt.Dimension; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.Toolkit; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLConnection; -import java.nio.charset.Charset; -import java.util.Locale; -import java.util.Random; - -import org.scijava.util.VersionUtils; - -import ij.IJ; -import ij.Prefs; - -/** - * Prepare and send a report to be logged by Google Analytics event tracking - *

- * Should be called in a PlugIn's run() method as - * UsageReporter.reportEvent(this).send() - *

- * - * @author Michael Doube - */ -public final class UsageReporter { - - private static final UsageReporter INSTANCE = new UsageReporter(); - - private static final String ga = "https://www.google-analytics.com/__utm.gif?"; - private static final String utmwv = "utmwv=5.2.5&"; - private static final String utmhn = "utmhn=bonej.org&"; - private static final String utmcs = "utmcs=" + Charset.defaultCharset() + "&"; - private static final String utmac = "utmac=UA-366405-8&"; - private static final String utmdt = "utmdt=bonej.org%20Usage%20Statistics&"; - private static final String utmt = "utmt=event&"; - private static final String utmul = "utmul=" + getLocaleString() + "&"; - private static final String utmje = "utmje=0&"; - private static final String utmfl = "utmfl=11.1%20r102&"; - private static final String utmr = "utmr=-&"; - private static final String utmp = "utmp=%2Fstats&"; - private static final Random random = new Random(); - private static String utmcnr = ""; - private static String utme; - private static String utmn; - private static String utmsr; - private static String utmvp; - private static String utmsc; - private static int session = 0; - private static String utms = "utms=" + session + "&"; - private static String utmcc; - private static long thisTime = 0; - private static long lastTime = 0; - private static String bonejSession = Prefs.get(ReporterOptions.SESSIONKEY, - Integer.toString(new Random().nextInt(1000))); - private static String utmhid; - - /** - * Constructor used by singleton pattern. Report variables that relate to - * single sessions are set here - */ - private UsageReporter() { - if (!Prefs.get(ReporterOptions.OPTOUTKEY, false)) return; - bonejSession = Prefs.get(ReporterOptions.SESSIONKEY, Integer.toString( - new Random().nextInt(1000))); - int inc = Integer.parseInt(bonejSession); - inc++; - bonejSession = Integer.toString(inc); - Prefs.set(ReporterOptions.SESSIONKEY, inc); - - final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - final GraphicsEnvironment ge = GraphicsEnvironment - .getLocalGraphicsEnvironment(); - int width = 0; - int height = 0; - if (!ge.isHeadlessInstance()) { - final GraphicsDevice[] screens = ge.getScreenDevices(); - for (final GraphicsDevice screen : screens) { - final GraphicsConfiguration[] gc = screen.getConfigurations(); - for (final GraphicsConfiguration g : gc) { - width = Math.max(g.getBounds().x + g.getBounds().width, width); - height = Math.max(g.getBounds().y + g.getBounds().height, height); - } - } - } - - utmsr = "utmsr=" + screenSize.width + "x" + screenSize.height + "&"; - utmvp = "utmvp=" + width + "x" + height + "&"; - utmsc = "utmsc=24-bit&"; - } - - /** - * Send the report to Google Analytics in the form of an HTTP request for a - * 1-pixel GIF with lots of parameters set - */ - public void send() { - if (!isAllowed()) return; - try { - final URL url = new URL(ga + utmwv + utms + utmn + utmhn + utmt + utme + utmcs + - utmsr + utmvp + utmsc + utmul + utmje + utmfl + utmcnr + utmdt + - utmhid + utmr + utmp + utmac + utmcc); - final URLConnection uc = url.openConnection(); - uc.setRequestProperty("User-Agent", userAgentString()); - //the next line appears to be necessary to complete the HTTP request - try (final BufferedReader reader = new BufferedReader(new InputStreamReader( - uc.getInputStream()))) { - if (IJ.debugMode) { - IJ.log(url.toString()); - IJ.log(uc.getRequestProperty("User-Agent")); - reader.lines().forEach(IJ::log); - } - } catch (final IOException e) { - IJ.error(e.getMessage()); - } - } - catch (final IOException e) { - if (IJ.debugMode) { - IJ.error(e.getMessage()); - } - } - } - - /** - * Sets the instance variables to appropriate values based on the system - * parameters and method arguments. - * - * @param category Google Analytics event category classification - * @param action Google Analytics event action classification - * @param label Google Analytics event label classification - * @param value Google Analytics event value - an integer used for sum and - * average statistics - * @return The instance of UsageReporter ready to send() a report - */ - private static UsageReporter reportEvent(final String category, - final String action, final String label, final Integer value) - { - if (!Prefs.get(ReporterOptions.OPTOUTKEY, false)) return INSTANCE; - utms = "utms=" + session + "&"; - session++; - final String val = (value == null) ? "" : "(" + value + ")"; - final String lab = (label == null) ? "" : label; - utme = "utme=5(" + category + "*" + action + "*" + lab + ")" + val + "&"; - utmn = "utmn=" + random.nextInt(Integer.MAX_VALUE) + "&"; - utmhid = "utmhid=" + random.nextInt(Integer.MAX_VALUE) + "&"; - - final long time = System.currentTimeMillis() / 1000; - lastTime = thisTime; - if (lastTime == 0) lastTime = time; - thisTime = time; - - if ("".equals(utmcnr)) utmcnr = "utmcn=1&"; - else utmcnr = "utmcr=1&"; - - utmcc = getCookieString(); - return INSTANCE; - } - - /** - * Prepare the instance for sending a report on a specific class; {@link Class#getName} - * is added to the 'action' field of the report, - * category is "Plugin Usage" and label is the version string generated by - * {@link org.scijava.util.VersionUtils#getVersion}. - * - * @param o Class to report on - * @return The instance of UsageReporter ready to send() a report - */ - public static UsageReporter reportEvent(final Object o) { - return reportEvent("Plugin%20Usage", o.getClass().getName(), VersionUtils.getVersion(o.getClass()), - null); - } - - /** - * Create a string of cookie data for the gif URL - * - * @return cookie string - */ - private static String getCookieString() { - // seems to be a bug in Prefs.getInt, so are Strings wrapped in - // Integer.toString() - final String cookie = Prefs.get(ReporterOptions.COOKIE, Integer.toString( - random.nextInt(Integer.MAX_VALUE))); - final String cookie2 = Prefs.get(ReporterOptions.COOKIE2, Integer.toString( - random.nextInt(Integer.MAX_VALUE))); - final String firstTime = Prefs.get(ReporterOptions.FIRSTTIMEKEY, Integer - .toString(random.nextInt(Integer.MAX_VALUE))); - // thisTime is not correct, but a best guess - return "utmcc=__utma%3D" + cookie + "." + cookie2 + "." + firstTime + "." + - lastTime + "." + thisTime + "." + bonejSession + "%3B%2B__utmz%3D" + - cookie + "." + thisTime + - ".79.42.utmcsr%3Dgoogle%7Cutmccn%3D(organic)%7C" + - "utmcmd%3Dorganic%7Cutmctr%3DBoneJ%20Usage%20Reporter%3B"; - } - - private static String getLocaleString() { - String locale = Locale.getDefault().toString(); - locale = locale.replace("_", "-"); - locale = locale.toLowerCase(Locale.ENGLISH); - return locale; - } - - private boolean isAllowed() { - if (!Prefs.get(ReporterOptions.OPTOUTSET, false)) new ReporterOptions().run( - ""); - return Prefs.get(ReporterOptions.OPTOUTKEY, true); - } - - private static String userAgentString() { - final String os; - if (IJ.isMacintosh()) { - // Handle Mac OSes on PPC and Intel - String arch = System.getProperty("os.arch"); - if (arch.contains("x86") || arch.contains("i386")) arch = "Intel"; - else if (arch.contains("ppc")) arch = arch.toUpperCase(); - os = "Macintosh; " + arch + " " + System.getProperty("os.name") + " " + - System.getProperty("os.version"); - } - else if (IJ.isWindows()) { - // Handle Windows using the NT version number - os = "Windows NT " + System.getProperty("os.version"); - } - else { - // Handle Linux and everything else - os = System.getProperty("os.name") + " " + System.getProperty( - "os.version") + " " + System.getProperty("os.arch"); - } - - final String browser = "Java/" + System.getProperty("java.version"); - final String vendor = System.getProperty("java.vendor"); - final String locale = getLocaleString(); - - return browser + " (" + os + "; " + locale + ") " + vendor; - } -} diff --git a/Legacy/bonej/src/main/java/org/bonej/plugins/VoxelDepthChecker.java b/Legacy/bonej/src/main/java/org/bonej/plugins/VoxelDepthChecker.java index 357b84d1..00001e59 100644 --- a/Legacy/bonej/src/main/java/org/bonej/plugins/VoxelDepthChecker.java +++ b/Legacy/bonej/src/main/java/org/bonej/plugins/VoxelDepthChecker.java @@ -43,6 +43,5 @@ public void run(final String arg) { final ImagePlus imp = IJ.getImage(); if (null == imp) return; ImageCheck.dicomVoxelDepth(imp); - UsageReporter.reportEvent(this).send(); } } diff --git a/Legacy/bonej/src/main/resources/plugins.config b/Legacy/bonej/src/main/resources/plugins.config index 452273bf..1656e153 100644 --- a/Legacy/bonej/src/main/resources/plugins.config +++ b/Legacy/bonej/src/main/resources/plugins.config @@ -42,5 +42,3 @@ Plugins>BoneJ, "Slice Geometry", org.bonej.plugins.SliceGeometry Image>Stacks, "Check Voxel Depth", org.bonej.plugins.VoxelDepthChecker Image>Stacks, "Delete Slice Range", org.bonej.plugins.DeleteSliceRange - -Edit>Options, "BoneJ Usage (Legacy)", org.bonej.plugins.ReporterOptions diff --git a/Modern/wrapperPlugins/pom.xml b/Modern/wrapperPlugins/pom.xml index 31f2b743..28b8bc34 100644 --- a/Modern/wrapperPlugins/pom.xml +++ b/Modern/wrapperPlugins/pom.xml @@ -238,6 +238,8 @@ org.mockito mockito-core + + 4.11.0 test diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapper.java index d7e7de75..0d2925fe 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapper.java @@ -208,7 +208,6 @@ public void run() { shortestPaths.setCalibration(inputImage.getCalibration()); } } - reportUsage(); } private boolean hasNoSkeletons(final AnalyzeSkeleton_ analyzeSkeleton_) { diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnisotropyWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnisotropyWrapper.java index 2bceabb1..10e56337 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnisotropyWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/AnisotropyWrapper.java @@ -217,7 +217,6 @@ public void run() { } addResults(subspaces, ellipsoids); resultsTable = SharedTable.getTable(); - reportUsage(); } // region -- Helper methods -- diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/BoneJCommand.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/BoneJCommand.java index e7b32c09..94d00bdd 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/BoneJCommand.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/BoneJCommand.java @@ -38,21 +38,15 @@ import org.bonej.wrapperPlugins.wrapperUtils.Common; import org.bonej.wrapperPlugins.wrapperUtils.HyperstackUtils; import org.bonej.wrapperPlugins.wrapperUtils.HyperstackUtils.Subspace; -import org.bonej.wrapperPlugins.wrapperUtils.UsageReporter; import org.scijava.ItemIO; -import org.scijava.command.CommandService; import org.scijava.command.ContextCommand; import org.scijava.plugin.Parameter; -import org.scijava.log.LogService; -import org.scijava.plugin.PluginService; -import org.scijava.prefs.PrefService; import org.scijava.table.DefaultColumn; import org.scijava.table.Table; import static java.util.stream.Collectors.toList; public abstract class BoneJCommand extends ContextCommand { - private static UsageReporter reporter; protected List> subspaces; @@ -71,23 +65,4 @@ protected > List> find3DSubspaces( final ImgPlus bitImgPlus = Common.toBitTypeImgPlus(opService, image); return HyperstackUtils.split3DSubspaces(bitImgPlus).collect(toList()); } - - protected void reportUsage() { - if (reporter == null) { - initReporter(); - } - reporter.reportEvent(getClass().getName()); - } - - private void initReporter() { - final PrefService prefService = context().getService(PrefService.class); - final PluginService pluginService = context().getService(PluginService.class); - final CommandService commandService = context().getService(CommandService.class); - final LogService logService = context().getService(LogService.class); - reporter = UsageReporter.getInstance(prefService, pluginService, commandService, logService); - } - - static void setReporter(final UsageReporter reporter) { - BoneJCommand.reporter = reporter; - } } diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ConnectivityWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ConnectivityWrapper.java index fb4876f3..8216fb8c 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ConnectivityWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ConnectivityWrapper.java @@ -110,7 +110,6 @@ public void run() { subspaceConnectivity(label, subspace.interval); }); resultsTable = SharedTable.getTable(); - reportUsage(); } private void addResults(final String label, final double eulerCharacteristic, diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ElementFractionWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ElementFractionWrapper.java index aaf99658..de1be7ba 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ElementFractionWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ElementFractionWrapper.java @@ -118,7 +118,6 @@ public void run() { addResults(label, foregroundSize, totalSize, ratio); } resultsTable = SharedTable.getTable(); - reportUsage(); } private void findSubspaces(final ImgPlus inputImage) { diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapper.java index 80618f31..6f6b2ec0 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapper.java @@ -317,7 +317,6 @@ public void run() { } resultsTable = SharedTable.getTable(); statusService.showStatus("Ellipsoid Factor completed"); - reportUsage(); } private List divideOutput(final List outputList, final int repetitions) { diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FitEllipsoidWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FitEllipsoidWrapper.java index 1090eafb..40c7130b 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FitEllipsoidWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FitEllipsoidWrapper.java @@ -118,7 +118,6 @@ public void run() { } addResults(result.get()); resultsTable = SharedTable.getTable(); - reportUsage(); } private void addResults(final Ellipsoid ellipsoid) { diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FractalDimensionWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FractalDimensionWrapper.java index 12b73c0b..d1c93f14 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FractalDimensionWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/FractalDimensionWrapper.java @@ -171,7 +171,6 @@ public void run() { }); fillResultsTable(subspaces, dimensions, rSquared); resultsTable = SharedTable.getTable(); - reportUsage(); } // region -- Helper methods -- diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/IntertrabecularAngleWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/IntertrabecularAngleWrapper.java index c48d61b3..c0fdc9e0 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/IntertrabecularAngleWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/IntertrabecularAngleWrapper.java @@ -207,7 +207,6 @@ public void run() { addResults(radianMap); printEdgeCentroids(cleanGraph.getEdges()); printCulledEdgePercentages(pruningResult.b); - reportUsage(); } private void addResults(final Map anglesMap) { diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SkeletoniseWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SkeletoniseWrapper.java index dd61eafa..9549472c 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SkeletoniseWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SkeletoniseWrapper.java @@ -86,7 +86,6 @@ public void run() { statusService.showStatus("Skeletonise: skeletonising"); skeletoniser.setup("", skeleton); skeletoniser.run(null); - reportUsage(); } @SuppressWarnings("unused") diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceAreaWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceAreaWrapper.java index 265e4951..602a07de 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceAreaWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceAreaWrapper.java @@ -138,7 +138,6 @@ public void run() { } calculateAreas(meshes); resultsTable = SharedTable.getTable(); - reportUsage(); } /** diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceFractionWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceFractionWrapper.java index 7fe18a30..78a16f62 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceFractionWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/SurfaceFractionWrapper.java @@ -108,7 +108,6 @@ public void run() { statusService.showProgress(i, subspaces.size()); } resultsTable = SharedTable.getTable(); - reportUsage(); } // region -- Helper methods -- diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ThicknessWrapper.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ThicknessWrapper.java index d4bb6c70..f5e46009 100644 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ThicknessWrapper.java +++ b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/ThicknessWrapper.java @@ -141,7 +141,6 @@ public void run() { spacingMap.setLut(fire); } } - reportUsage(); } private void addMapResults(final ImagePlus map) { diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporter.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporter.java deleted file mode 100644 index e18c448d..00000000 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporter.java +++ /dev/null @@ -1,308 +0,0 @@ -/*- - * #%L - * High-level BoneJ2 commands. - * %% - * Copyright (C) 2015 - 2023 Michael Doube, BoneJ 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.bonej.wrapperPlugins.wrapperUtils; - -import java.awt.Dimension; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.Toolkit; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLConnection; -import java.nio.charset.Charset; -import java.util.Locale; -import java.util.Random; -import java.util.concurrent.ExecutionException; - -import org.scijava.command.CommandModule; -import org.scijava.command.CommandService; -import org.scijava.log.Logger; -import org.scijava.plugin.PluginService; -import org.scijava.prefs.PrefService; - -/** - * Prepares and sends a report about BoneJ usage to be logged by - * Google Analytics event tracking - * - * @author Michael Doube - * @author Richard Domander - */ -// TODO Instead of System.out print debug stuff with LogService -// TODO Instead of System.out print status messages with StatusService -// Don't make class final - breaks Mockito -public class UsageReporter { - - private static final String ga = "https://www.google-analytics.com/__utm.gif?"; - private static final String utmwv = "utmwv=5.2.5&"; - private static final String utmhn = "utmhn=bonej.org&"; - private static final String utmcs = "utmcs=" + Charset.defaultCharset() + "&"; - private static final String utmac = "utmac=UA-366405-8&"; - private static final String utmdt = "utmdt=bonej.org%20Usage%20Statistics&"; - private static final String utmt = "utmt=event&"; - private static final String utmul = "utmul=" + getLocaleString() + "&"; - private static final String utmje = "utmje=0&"; - private static final String utmr = "utmr=-&"; - private static final String utmp = "utmp=%2Fstats&"; - private static final Random random = new Random(); - private static String utmcnr = ""; - private static String utmsr; - private static String utmvp; - private static String utmsc; - /** Incremented on each new event */ - private static int session; - private static long thisTime; - private static long lastTime; - private static boolean isFirstRun = true; - private static PrefService prefs; - private static PluginService plugins; - private static CommandService commandService; - private static UsageReporter instance; - private static String utms; - private static String utmn; - private static String utme; - private static String utmhid; - private static String utmcc; - private static Logger logger; - - private UsageReporter() {} - - /** - * Reports a the usage of a plug-in to bonej.org - * - * @param className Name of the reporting plug-in's class - */ - public void reportEvent(final String className) { - if (!isAllowed()) { - logger.debug("Usage reporting forbidden by user"); - return; - } - final String version = plugins.getPlugin(className).getVersion(); - reportEvent(className, version); - } - - public static UsageReporter getInstance(final PrefService prefs, - final PluginService plugins, final CommandService commandService, final Logger logger) - { - if (prefs == null || plugins == null || commandService == null || logger == null) { - throw new NullPointerException("Services cannot be null"); - } - if (instance == null) { - instance = new UsageReporter(); - } - UsageReporter.commandService = commandService; - UsageReporter.plugins = plugins; - UsageReporter.prefs = prefs; - UsageReporter.logger = logger; - return instance; - } - - /** - * Create a string of cookie data for the gif URL - * - * @return cookie string - */ - private static String getCookieString(final PrefService prefs) { - final int cookie = prefs.getInt(UsageReporterOptions.class, - UsageReporterOptions.COOKIE, random.nextInt(Integer.MAX_VALUE)); - final int cookie2 = prefs.getInt(UsageReporterOptions.class, - UsageReporterOptions.COOKIE2, random.nextInt(Integer.MAX_VALUE)); - final long firstTime = prefs.getInt(UsageReporterOptions.class, - UsageReporterOptions.FIRSTTIMEKEY, random.nextInt(Integer.MAX_VALUE)); - final int bonejSession = prefs.getInt(UsageReporterOptions.class, - UsageReporterOptions.SESSIONKEY, 0); - // thisTime is not correct, but a best guess - return "utmcc=__utma%3D" + cookie + "." + cookie2 + "." + firstTime + "." + - lastTime + "." + thisTime + "." + bonejSession + "%3B%2B__utmz%3D" + - cookie + "." + thisTime + - ".79.42.utmcsr%3Dgoogle%7Cutmccn%3D(organic)%7C" + - "utmcmd%3Dorganic%7Cutmctr%3DBoneJ%20Usage%20Reporter%3B"; - } - - private static String getLocaleString() { - String locale = Locale.getDefault().toString(); - locale = locale.replace("_", "-"); - locale = locale.toLowerCase(Locale.ENGLISH); - return locale; - } - - private static void initSessionVariables(final PrefService prefs) { - logger.debug("First run of Usage Reporter for this BoneJ session"); - final int bonejSession = prefs.getInt(UsageReporterOptions.class, - UsageReporterOptions.SESSIONKEY, 0); - logger.debug("bonejSession = " + bonejSession); - prefs.put(UsageReporterOptions.class, UsageReporterOptions.SESSIONKEY, - bonejSession + 1); - final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - final GraphicsEnvironment ge = GraphicsEnvironment - .getLocalGraphicsEnvironment(); - int width = 0; - int height = 0; - if (!ge.isHeadlessInstance()) { - final GraphicsDevice[] screens = ge.getScreenDevices(); - for (final GraphicsDevice screen : screens) { - final GraphicsConfiguration[] gc = screen.getConfigurations(); - for (final GraphicsConfiguration g : gc) { - width = Math.max(g.getBounds().x + g.getBounds().width, width); - height = Math.max(g.getBounds().y + g.getBounds().height, height); - } - } - } - utmsr = "utmsr=" + screenSize.width + "x" + screenSize.height + "&"; - utmvp = "utmvp=" + width + "x" + height + "&"; - utmsc = "utmsc=24-bit&"; - isFirstRun = false; - } - - /** - * Sets the instance variables to appropriate values based on the system - * parameters and method arguments and makes the URL request to Google - * - * @param action Google Analytics event action classification - * @param label Google Analytics event label classification - */ - private static void reportEvent(final String action, final String label) { - if (isFirstRun) { - initSessionVariables(prefs); - } - - // set - utms = "utms=" + session + "&"; - session++; - utme = "utme=5(" + "Plugin%20Usage" + "*" + action + "*" + label + ")&"; - utmn = "utmn=" + random.nextInt(Integer.MAX_VALUE) + "&"; - utmhid = "utmhid=" + random.nextInt(Integer.MAX_VALUE) + "&"; - - final long time = System.currentTimeMillis() / 1000; - lastTime = thisTime; - if (lastTime == 0) lastTime = time; - thisTime = time; - - if ("".equals(utmcnr)) utmcnr = "utmcn=1&"; - else utmcnr = "utmcr=1&"; - - utmcc = getCookieString(prefs); - send(); - } - - /** - * Send the report to Google Analytics in the form of an HTTP request for a - * 1-pixel GIF with lots of parameters set - */ - private static void send() { - logger.debug("Sending report"); - try { - logger.debug("Usage reporting approved by user, preparing URL"); - final URL url = new URL(ga + utmwv + utms + utmn + utmhn + utmt + utme + utmcs + - utmsr + utmvp + utmsc + utmul + utmje + utmcnr + utmdt + utmhid + utmr + - utmp + utmac + utmcc); - final URLConnection uc = url.openConnection(); - uc.setRequestProperty("User-Agent", userAgentString()); - logReport(url, uc); - } - catch (final IOException e) { - logger.trace(e.getMessage()); - } - } - - private static void logReport(final URL url, final URLConnection uc) { - logger.debug(url); - logger.debug(uc.getRequestProperty("User-Agent")); - try (final BufferedReader reader = new BufferedReader(new InputStreamReader( - uc.getInputStream()))) - { - reader.lines().forEach(line -> logger.debug(line)); - } - catch (final IOException e) { - logger.trace(e.getMessage()); - } - } - - private static String userAgentString() { - final String os; - final String osName = System.getProperty("os.name"); - final boolean isWin = osName.startsWith("Windows"); - final boolean isMac = !isWin && osName.startsWith("Mac"); - if (isMac) { - // Handle Mac OSes on PPC and Intel - String arch = System.getProperty("os.arch"); - if (arch.contains("x86") || arch.contains("i386")) arch = "Intel"; - else if (arch.contains("ppc")) arch = arch.toUpperCase(); - os = "Macintosh; " + arch + " " + System.getProperty("os.name") + " " + - System.getProperty("os.version"); - } - else if (isWin) { - // Handle Windows using the NT version number - os = "Windows NT " + System.getProperty("os.version"); - } - else { - // Handle Linux and everything else - os = osName + " " + System.getProperty("os.version") + " " + System - .getProperty("os.arch"); - } - - final String browser = "Java/" + System.getProperty("java.version"); - final String vendor = System.getProperty("java.vendor"); - final String locale = getLocaleString(); - - return browser + " (" + os + "; " + locale + ") " + vendor; - } - - /** - * Check whether user has given permission to collect usage data - * - * @return true only if the user has given explicit permission to send usage - * data - */ - boolean isAllowed() { - final boolean permissionSought = prefs.getBoolean( - UsageReporterOptions.class, UsageReporterOptions.OPTINSET, false); - if (!permissionSought) { - logger.debug("User permission has not been sought, requesting it..."); - try { - final CommandModule module = commandService.run( - UsageReporterOptions.class, true).get(); - if (module.isCanceled()) { - return false; - } - } - catch (final InterruptedException | ExecutionException e) { - logger.trace(e); - return false; - } - } - return prefs.getBoolean(UsageReporterOptions.class, - UsageReporterOptions.OPTINKEY, false); - } -} diff --git a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporterOptions.java b/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporterOptions.java deleted file mode 100644 index 25b058f5..00000000 --- a/Modern/wrapperPlugins/src/main/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporterOptions.java +++ /dev/null @@ -1,137 +0,0 @@ -/*- - * #%L - * High-level BoneJ2 commands. - * %% - * Copyright (C) 2015 - 2023 Michael Doube, BoneJ 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.bonej.wrapperPlugins.wrapperUtils; - -import java.io.IOException; -import java.net.URL; -import java.util.Random; - -import org.scijava.ItemVisibility; -import org.scijava.command.Command; -import org.scijava.command.CommandService; -import org.scijava.command.ContextCommand; -import org.scijava.log.LogService; -import org.scijava.platform.PlatformService; -import org.scijava.plugin.Parameter; -import org.scijava.plugin.Plugin; -import org.scijava.plugin.PluginService; -import org.scijava.prefs.PrefService; -import org.scijava.ui.UIService; -import org.scijava.widget.Button; - -/** - * Handles persistent settings such as user permission state. Preferences are - * stored in their native format (long, int, boolean, etc.) - * - * @author Michael Doube - * @author Richard Domander - */ -@Plugin(type = Command.class, menuPath = "Edit>Options>BoneJ Usage (Modern)") -public class UsageReporterOptions extends ContextCommand { - - /** set to true if user permission has been requested */ - static final String OPTINSET = "bonej2.report.option.set"; - /** Set to false if reporting is not allowed */ - static final String OPTINKEY = "bonej2.allow.reporter"; - static final String COOKIE = "bonej2.report.cookie"; - static final String COOKIE2 = "bonej2.report.cookie2"; - /** time of first visit in seconds */ - static final String FIRSTTIMEKEY = "bonej2.report.firstvisit"; - /** unique ID for this particular BoneJ session */ - static final String SESSIONKEY = "bonej2.report.bonejsession"; - private static final String IJSESSIONKEY = "bonej2.report.ijsession"; - // TODO Make into one string (format with HTML) - @Parameter(visibility = ItemVisibility.MESSAGE, persist = false) - private String message1 = "Allow usage data collection?"; - @Parameter(visibility = ItemVisibility.MESSAGE, persist = false) - private String message2 = "BoneJ would like to collect data on"; - @Parameter(visibility = ItemVisibility.MESSAGE, persist = false) - private String message3 = - "which plugins are being used, to direct development"; - @Parameter(visibility = ItemVisibility.MESSAGE, persist = false) - private String message4 = "and promote BoneJ to funders."; - @Parameter(visibility = ItemVisibility.MESSAGE, persist = false) - private String message5 = "If you agree to participate please check the box."; - @Parameter(label = "Opt in to usage data collection", - description = "Can BoneJ send usage data?", persistKey = OPTINKEY) - private boolean optIn; - @Parameter(visibility = ItemVisibility.MESSAGE, persist = false) - private String helpMessage = "For more information click Help."; - @Parameter(label = "Help", description = "More about data collection", callback = "showHelpPage") - private Button button; - @Parameter - private PrefService prefs; - @Parameter - private LogService logService; - @Parameter - private PluginService pluginService; - @Parameter - private CommandService commandService; - @Parameter - private UIService uiService; - @Parameter - private PlatformService platformService; - private UsageReporter reporter; - - @Override - public void run() { - if (!optIn) { - // Wipe persistent data on opt-out - logService.debug("User has opted out of data collection\n"); - prefs.clear(getClass()); - prefs.put(getClass(), OPTINSET, true); - return; - } - - logService.debug("User has opted in to data collection\n"); - prefs.put(getClass(), OPTINKEY, true); - prefs.put(getClass(), COOKIE, new Random().nextInt(Integer.MAX_VALUE)); - prefs.put(getClass(), COOKIE2, new Random().nextInt(Integer.MAX_VALUE)); - prefs.put(getClass(), FIRSTTIMEKEY, System.currentTimeMillis() / 1000); - prefs.put(getClass(), SESSIONKEY, 1); - prefs.put(getClass(), IJSESSIONKEY, 1); - prefs.put(getClass(), OPTINSET, true); - if (reporter == null) { - reporter = UsageReporter.getInstance(prefs, pluginService, commandService, logService); - } - reporter.reportEvent(getClass().getName()); - } - - @SuppressWarnings("unused") - private void showHelpPage() { - try { - platformService.open(new URL("https://imagej.github.io/plugins/bonej#usage-reporting")); - } catch (final IOException e) { - uiService.showDialog("Something went wrong while opening the help page. Please try again."); - logService.trace(e); - } - } -} diff --git a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AbstractWrapperTest.java b/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AbstractWrapperTest.java index 9f072c3d..3aa95436 100644 --- a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AbstractWrapperTest.java +++ b/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AbstractWrapperTest.java @@ -31,7 +31,6 @@ import net.imagej.ImageJ; import org.bonej.utilities.SharedTable; -import org.bonej.wrapperPlugins.wrapperUtils.UsageReporter; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -53,7 +52,6 @@ */ public abstract class AbstractWrapperTest { private static ImageJ imageJ; - protected static final UsageReporter MOCK_REPORTER = mock(UsageReporter.class); protected static final UserInterface MOCK_UI = mock(UserInterface.class); private static CommandService commandService; @@ -69,26 +67,22 @@ protected static ImageJ imageJ() { public static void basicOneTimeSetup() { imageJ = new ImageJ(); commandService = imageJ.command(); - BoneJCommand.setReporter(MOCK_REPORTER); } @Before public void setup() { imageJ.ui().setHeadless(false); imageJ.ui().setDefaultUI(MOCK_UI); - doNothing().when(MOCK_REPORTER).reportEvent(anyString()); } @After public void tearDown() { Mockito.reset(MOCK_UI); - Mockito.reset(MOCK_REPORTER); SharedTable.reset(); } @AfterClass public static void basicOneTimeTearDown() { - BoneJCommand.setReporter(null); imageJ.context().dispose(); imageJ = null; commandService = null; diff --git a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapperTest.java b/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapperTest.java index 669c8009..e74c5eeb 100644 --- a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapperTest.java +++ b/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/AnalyseSkeletonWrapperTest.java @@ -41,17 +41,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.after; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import ij.IJ; import ij.ImagePlus; import ij.gui.NewImage; import ij.measure.Calibration; -import java.io.File; import java.util.Collection; import java.util.List; import java.util.concurrent.ExecutionException; @@ -357,7 +354,7 @@ public void testTimeDimensionCancelsPlugin() throws Exception { } @Test - public void testCancelledRunDoesNotReport() throws ExecutionException, + public void testEmptyImageCancels() throws ExecutionException, InterruptedException { // SETUP @@ -372,11 +369,10 @@ public void testCancelledRunDoesNotReport() throws ExecutionException, // VERIFY assertTrue("Sanity check failed: method didn't cancel", module .isCanceled()); - verify(MOCK_REPORTER, timeout(1000).times(0)).reportEvent(anyString()); } @Test - public void testSuccessfulRunReports() throws ExecutionException, + public void testSensibleInputDoesNotCancel() throws ExecutionException, InterruptedException { // SETUP @@ -390,6 +386,5 @@ public void testSuccessfulRunReports() throws ExecutionException, // VERIFY assertFalse("Sanity check failed: method cancelled", module.isCanceled()); - verify(MOCK_REPORTER, timeout(1000)).reportEvent(anyString()); } } diff --git a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapperTest.java b/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapperTest.java index 65d76281..d2965c87 100644 --- a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapperTest.java +++ b/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/EllipsoidFactorWrapperTest.java @@ -30,9 +30,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; import net.imagej.axis.Axes; import net.imagej.axis.DefaultLinearAxis; @@ -80,7 +77,7 @@ public void testNullImageCancelsConnectivity() { @Category(org.bonej.wrapperPlugins.SlowWrapperTest.class) @Test - public void testCancelledRunDoesNotReport() throws ExecutionException, + public void testEmptyImageCancels() throws ExecutionException, InterruptedException { // SETUP @@ -102,14 +99,13 @@ public void testCancelledRunDoesNotReport() throws ExecutionException, final String reason = module.getCancelReason(); assertEquals("EF should have cancelled because there are no ellipsoids in an empty image", EllipsoidFactorWrapper.NO_ELLIPSOIDS_FOUND, reason); - verify(MOCK_REPORTER, timeout(1000).times(0)).reportEvent(anyString()); } // run(nvectors=100 vectorincrement=0.435 skipratio=1 contactsensitivity=1 maxiterations=100 maxdrift=1.73 minimumsemiaxis=1.0 runs=1 weightedaveragen=1 seedondistanceridge=true distancethreshold=0.6 seedontopologypreserving=false); @Category(org.bonej.wrapperPlugins.SlowWrapperTest.class) @Test - public void testSuccessfulRunReports() throws ExecutionException, InterruptedException { + public void testSensibleInputDoesNotCancel() throws ExecutionException, InterruptedException { final DefaultLinearAxis xAxis = new DefaultLinearAxis(Axes.X, "", 1.0); final DefaultLinearAxis yAxis = new DefaultLinearAxis(Axes.Y, "", 1.0); final DefaultLinearAxis zAxis = new DefaultLinearAxis(Axes.Z, "", 1.0); @@ -124,7 +120,6 @@ public void testSuccessfulRunReports() throws ExecutionException, InterruptedExc false).get(); assertFalse("Sanity check failed: method cancelled", module.isCanceled()); - verify(MOCK_REPORTER, timeout(1000)).reportEvent(anyString()); } @Test @@ -142,7 +137,6 @@ public void testImgToByteArray(){ @BeforeClass public static void oneTimeSetup() { - EllipsoidFactorWrapper.setReporter(MOCK_REPORTER); } private static Img createSphereImg() { diff --git a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporterTest.java b/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporterTest.java deleted file mode 100644 index 74a7ab82..00000000 --- a/Modern/wrapperPlugins/src/test/java/org/bonej/wrapperPlugins/wrapperUtils/UsageReporterTest.java +++ /dev/null @@ -1,180 +0,0 @@ -/*- - * #%L - * High-level BoneJ2 commands. - * %% - * Copyright (C) 2015 - 2023 Michael Doube, BoneJ 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.bonej.wrapperPlugins.wrapperUtils; - -import static org.bonej.wrapperPlugins.wrapperUtils.UsageReporterOptions.OPTINKEY; -import static org.bonej.wrapperPlugins.wrapperUtils.UsageReporterOptions.OPTINSET; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import org.bonej.wrapperPlugins.SlowWrapperTest; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.scijava.command.CommandModule; -import org.scijava.command.CommandService; -import org.scijava.log.LogService; -import org.scijava.plugin.PluginService; -import org.scijava.prefs.PrefService; - -/** - * Tests for {@link UsageReporter}. - * - * @author Richard Domander - */ -public class UsageReporterTest { - - @Category(SlowWrapperTest.class) - @Test - public void testIsAllowedOptInFalse() { - // SETUP - final PrefService prefs = mock(PrefService.class); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINSET, false)) - .thenReturn(true); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINKEY, false)) - .thenReturn(false); - final PluginService plugins = mock(PluginService.class); - final CommandService commands = mock(CommandService.class); - final LogService logger = mock(LogService.class); - final UsageReporter reporter = UsageReporter.getInstance(prefs, plugins, commands, logger); - - // EXECUTE - final boolean allowed = reporter.isAllowed(); - - // VERIFY - // OPTINSET save data should been queried - verify(prefs, timeout(1000)).getBoolean(UsageReporterOptions.class, - OPTINSET, false); - // OPTINKEY save data should been queried - verify(prefs, timeout(1000)).getBoolean(UsageReporterOptions.class, - OPTINKEY, false); - assertFalse(allowed); - } - - @Category(SlowWrapperTest.class) - @Test - public void testIsAllowedOptInTrue() { - // SETUP - final PrefService prefs = mock(PrefService.class); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINSET, false)) - .thenReturn(true); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINKEY, false)) - .thenReturn(true); - final PluginService plugins = mock(PluginService.class); - final CommandService commands = mock(CommandService.class); - final LogService logger = mock(LogService.class); - final UsageReporter reporter = UsageReporter.getInstance(prefs, plugins, commands, logger); - - // EXECUTE - final boolean allowed = reporter.isAllowed(); - - // VERIFY - // OPTINSET save data should been queried - verify(prefs, timeout(1000)).getBoolean(UsageReporterOptions.class, - OPTINSET, false); - // OPTINKEY save data should been queried - verify(prefs, timeout(1000)).getBoolean(UsageReporterOptions.class, - OPTINKEY, false); - assertTrue(allowed); - } - - @Category(SlowWrapperTest.class) - @Test - public void testIsAllowedPermissionNotSought() throws ExecutionException, - InterruptedException - { - // SETUP - final PrefService prefs = mock(PrefService.class); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINSET, false)) - .thenReturn(false); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINKEY, false)) - .thenReturn(false); - final PluginService plugins = mock(PluginService.class); - @SuppressWarnings("unchecked") - final Future future = mock(Future.class); - final CommandModule module = mock(CommandModule.class); - when(module.isCanceled()).thenReturn(false); - when(future.get()).thenReturn(module); - final CommandService commands = mock(CommandService.class); - when(commands.run(UsageReporterOptions.class, true)).thenReturn(future); - final LogService logger = mock(LogService.class); - final UsageReporter reporter = UsageReporter.getInstance(prefs, plugins, commands, logger); - - // EXECUTE - final boolean allowed = reporter.isAllowed(); - - // VERIFY - // UsageReporterOptions should have been run - verify(commands, timeout(1000)).run(UsageReporterOptions.class, true); - // OPTINSET save data should been queried - verify(prefs, timeout(1000)).getBoolean(UsageReporterOptions.class, - OPTINSET, false); - // OPTINKEY save data should been queried - verify(prefs, timeout(1000)).getBoolean(UsageReporterOptions.class, - OPTINKEY, false); - assertFalse(allowed); - } - - @Test - public void testIsAllowedPermissionSought() throws ExecutionException, - InterruptedException - { - // SETUP - final PrefService prefs = mock(PrefService.class); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINSET, false)) - .thenReturn(true); - when(prefs.getBoolean(UsageReporterOptions.class, OPTINKEY, false)) - .thenReturn(false); - final PluginService plugins = mock(PluginService.class); - @SuppressWarnings("unchecked") - final Future future = mock(Future.class); - final CommandModule module = mock(CommandModule.class); - when(module.isCanceled()).thenReturn(false); - when(future.get()).thenReturn(module); - final CommandService commands = mock(CommandService.class); - when(commands.run(UsageReporterOptions.class, true)).thenReturn(future); - final LogService logger = mock(LogService.class); - final UsageReporter reporter = UsageReporter.getInstance(prefs, plugins, commands, logger); - - // EXECUTE - reporter.isAllowed(); - - // VERIFY - // UsageReporterOptions should not have been run - verify(commands, timeout(1000).times(0)).run(UsageReporterOptions.class, - true); - } -}