From ebc1d9f0dfd2d54c4ae67e29e40eb00117069f7c Mon Sep 17 00:00:00 2001 From: sroughley Date: Tue, 1 Dec 2020 17:48:03 +0000 Subject: [PATCH] Update to v1.27.4 * Add RDKitRuntimeExceptionHandler class to allow RDKit version before 4.1 or after 4.1 to work seemlessly --- .../META-INF/MANIFEST.MF | 2 +- .../rdkit/RDKitRuntimeExceptionHandler.java | 229 ++ .../META-INF/MANIFEST.MF | 7 +- .../mmp/fragmentors/ROMolFragmentFactory.java | 16 +- .../nodes/maxcuts/MmpMaxCutsNodeModel.java | 16 +- .../AbstractMatchedPairsFilterNodeModel.java | 16 +- ...dkitMatchedPairsMultipleCutsNodeModel.java | 17 +- ...actParallelRdkitMMPFragment3NodeModel.java | 44 +- .../RWMolFragmentationFactory.java | 24 +- .../RWMolFragmentationUtilsFactory.java | 43 +- .../META-INF/MANIFEST.MF | 6 +- .../rdkitgenerate/RdkitConfgenNodeModel.java | 5 +- .../META-INF/MANIFEST.MF | 2 +- com.vernalis.knime.core/META-INF/MANIFEST.MF | 2 +- .../components/DialogComponentIntRange.java | 733 +++--- ...ingsModelStringArrayFlowVarReplacable.java | 343 +-- .../com/vernalis/knime/misc/ArrayUtils.java | 2168 +++++++++-------- .../src/com/vernalis/knime/misc/EitherOr.java | 396 +-- .../META-INF/MANIFEST.MF | 2 +- com.vernalis.knime.feature/feature.xml | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 2 +- com.vernalis.knime.io/META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../feature.xml | 2 +- com.vernalis.knime/META-INF/MANIFEST.MF | 2 +- com.vernalis.knime/dir_conflicts.prej | 6 - 31 files changed, 2281 insertions(+), 1818 deletions(-) create mode 100644 com.vernalis.knime.chem.core/src/com/vernalis/knime/chem/rdkit/RDKitRuntimeExceptionHandler.java delete mode 100644 com.vernalis.knime/dir_conflicts.prej diff --git a/com.vernalis.knime.chem.core/META-INF/MANIFEST.MF b/com.vernalis.knime.chem.core/META-INF/MANIFEST.MF index 40dfa3d7..6c004487 100644 --- a/com.vernalis.knime.chem.core/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.chem.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.chem.core; singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: vernalischemcore.jar Bundle-Activator: com.vernalis.knime.chem.core.VernalisChemCoreNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.chem.core/src/com/vernalis/knime/chem/rdkit/RDKitRuntimeExceptionHandler.java b/com.vernalis.knime.chem.core/src/com/vernalis/knime/chem/rdkit/RDKitRuntimeExceptionHandler.java new file mode 100644 index 00000000..2dfb4ef3 --- /dev/null +++ b/com.vernalis.knime.chem.core/src/com/vernalis/knime/chem/rdkit/RDKitRuntimeExceptionHandler.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright (c) 2020, Vernalis (R&D) Ltd + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, Version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + ******************************************************************************/ +package com.vernalis.knime.chem.rdkit; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.RDKit.AtomKekulizeException; +import org.RDKit.AtomSanitizeException; +import org.RDKit.AtomValenceException; +import org.RDKit.ChemicalReactionException; +import org.RDKit.ChemicalReactionParserException; +import org.RDKit.ConformerException; +import org.RDKit.GenericRDKitException; +import org.RDKit.KekulizeException; +import org.RDKit.KeyErrorException; +import org.RDKit.MolPicklerException; +import org.RDKit.MolSanitizeException; +import org.RDKit.MolSanitizeException_Vect; +import org.RDKit.SmilesParseException; + +/** + * This class wraps RDKit {@link RuntimeException}s and obtains the message via + * reflection from either the {@code message} or {@code what} methods. If + * neither method is found, it falls back on the standard {@link #getMessage()} + * method. The original 'cause' RDKit exception is available via + * {@link #getCause()} + * + * @author S.Roughley knime@vernalis.com + * @since com.vernalis.knime.chem.core 1.27.4 + */ +@SuppressWarnings("serial") +public class RDKitRuntimeExceptionHandler extends RuntimeException { + + // The following from RDKitExceptions.i + /** + * Constructor from {@link ChemicalReactionException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(ChemicalReactionException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link ChemicalReactionParserException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(ChemicalReactionParserException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link ConformerException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(ConformerException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link MolPicklerException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(MolPicklerException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link MolSanitizeException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(MolSanitizeException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link SmilesParseException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(SmilesParseException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link KeyErrorException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(KeyErrorException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link GenericRDKitException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(GenericRDKitException e) { + this((RuntimeException) e); + } + + // The following subclasses of MolSanitizeException are defined in + // SanitException.i + /** + * Constructor from {@link AtomSanitizeException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(AtomSanitizeException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link AtomValenceException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(AtomValenceException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link AtomKekulizeException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(AtomKekulizeException e) { + this((RuntimeException) e); + } + + /** + * Constructor from {@link KekulizeException} + * + * @param e + * The cause + */ + public RDKitRuntimeExceptionHandler(KekulizeException e) { + this((RuntimeException) e); + } + + private RDKitRuntimeExceptionHandler(RuntimeException cause) { + super(getRDKitMessage(cause), cause); + + } + + /** + * @return The class of the initial RDKit Exception + */ + public Class getRDKitExceptionClass() { + return getCause().getClass(); + } + + private static String getRDKitMessage(RuntimeException cause) { + Class clazz = cause.getClass(); + String msg = null; + Method mtd = null; + methodloop: for (Method m : clazz.getMethods()) { + switch (m.getName()) { + case "what": + case "message": + mtd = m; + break methodloop; + default: + // Nothing to do + } + } + if (mtd != null) { + mtd.setAccessible(true); + try { + msg = (String) mtd.invoke(cause); + } catch (ClassCastException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + // Do nothing + } + } + if (msg == null) { + msg = cause.getMessage(); + } + return msg; + } + + /** + * Static factory method to handle {@link MolSanitizeException_Vect} + * + * @param msev + * The cause vector + * @return A List of handlers for the individual + * {@link MolSanitizeException}s + */ + public static List + fromMolSanitizeExceptionVect(MolSanitizeException_Vect msev) { + List retVal = new ArrayList<>(); + for (int i = 0; i < msev.size(); i++) { + retVal.add(new RDKitRuntimeExceptionHandler(msev.get(i))); + } + return retVal; + } +} diff --git a/com.vernalis.knime.chem.mmp/META-INF/MANIFEST.MF b/com.vernalis.knime.chem.mmp/META-INF/MANIFEST.MF index ecbace1c..f5a25e85 100644 --- a/com.vernalis.knime.chem.mmp/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.chem.mmp/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.chem.mmp;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: matchedpairsmultiplecuts.jar Bundle-Activator: com.vernalis.knime.mmp.MatchedPairsMultipleCutsNodePlugin Bundle-Vendor: %Bundle-Vendor @@ -12,11 +12,12 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.13.0,4.0.0)", org.knime.base;bundle-version="[3.0.0,5.0.0)", org.knime.chem.base;bundle-version="[3.0.0,5.0.0)", org.knime.chem.types;bundle-version="[3.0.0,5.0.0)", - org.rdkit.knime.types;bundle-version="[4.1.0,5.0.0)", + org.rdkit.knime.types;bundle-version="[4.0.0,5.0.0)", com.vernalis.knime.core;bundle-version="[1.5.0,2.0.0)", org.eclipse.osgi;bundle-version="[3.12.0,4.0.0)", org.knime.ext.svg;bundle-version="[3.0.0,5.0.0)", - com.vernalis.knime.chem.speedysmiles;bundle-version="[1.12.2,2.0.0)" + com.vernalis.knime.chem.speedysmiles;bundle-version="[1.12.2,2.0.0)", + com.vernalis.knime.chem.core;bundle-version="[1.27.4,2.0.0)" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Export-Package: com.vernalis.knime.mmp, diff --git a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/fragmentors/ROMolFragmentFactory.java b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/fragmentors/ROMolFragmentFactory.java index c022d7dc..9b495502 100644 --- a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/fragmentors/ROMolFragmentFactory.java +++ b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/fragmentors/ROMolFragmentFactory.java @@ -47,6 +47,7 @@ import org.RDKit.UInt_Vect; import org.knime.core.node.NodeLogger; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.mmp.MulticomponentSmilesFragmentParser; import com.vernalis.knime.mmp.RDKitBondIdentifier; import com.vernalis.knime.swiggc.SWIGObjectGarbageCollector; @@ -1153,8 +1154,11 @@ private void assignAPChirality(RWMol component, int localGcWave) RDKFuncs.assignStereochemistry(component, false, true, true); } catch (MolSanitizeException e) { if (verboseLogging) { - logger.info("Problem assigning double bond geometry" - + e.what() == null ? "" : e.what()); + String msg = new RDKitRuntimeExceptionHandler(e).getMessage(); + logger.info( + "Problem assigning double bond geometry" + msg == null + ? "" + : msg); } return; } catch (Exception e) { @@ -1237,10 +1241,10 @@ private void assignCreatedDblBondGeometry(RWMol component, RDKFuncs.findPotentialStereoBonds(component, false); System.out.println("Found potential stereobonds..."); } catch (MolSanitizeException e) { - if (verboseLogging) { - logger.info("Problem assigning double bond geometry" - + e.what() == null ? "" : e.what()); - } + String msg = new RDKitRuntimeExceptionHandler(e).getMessage(); + logger.info( + "Problem assigning double bond geometry" + msg == null ? "" + : msg); return; } catch (Exception e) { if (verboseLogging) { diff --git a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/maxcuts/MmpMaxCutsNodeModel.java b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/maxcuts/MmpMaxCutsNodeModel.java index 99867e86..0ed46e4d 100644 --- a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/maxcuts/MmpMaxCutsNodeModel.java +++ b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/maxcuts/MmpMaxCutsNodeModel.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; -import org.RDKit.GenericRDKitException; import org.RDKit.MolSanitizeException; import org.RDKit.RDKFuncs; import org.RDKit.ROMol; @@ -53,6 +52,7 @@ import org.rdkit.knime.types.RDKitMolValue; import com.vernalis.exceptions.RowExecutionException; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.mmp.FragmentationTypes; import com.vernalis.knime.mmp.MatchedPairsMultipleCutsNodePlugin; import com.vernalis.knime.mmp.RDKitFragmentationUtils; @@ -240,19 +240,11 @@ protected ROMol getROMolFromCell(DataCell cell) } catch (MolSanitizeException e) { // MolSanitizeException returns null for #getMessage() throw new RowExecutionException("Error in sanitizing molecule: " - + ((StringValue) cell).getStringValue() + " : " + e.what()); + + ((StringValue) cell).getStringValue() + " : " + + new RDKitRuntimeExceptionHandler(e).getMessage()); } catch (Exception e) { String msg = e.getMessage(); - if (msg == null || "".equals(msg)) { - // Try to do something useful if we have a different RDKit - // Exception - at least try to report the error type! - msg = e.getClass().getSimpleName(); - try { - msg += " : " + ((GenericRDKitException) e).what(); - } catch (Exception e1) { - // Do nothing - } - } + if (msg.equals("Cell is not a recognised molecule type")) { throw new RowExecutionException(msg); } else { diff --git a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/prefilter/AbstractMatchedPairsFilterNodeModel.java b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/prefilter/AbstractMatchedPairsFilterNodeModel.java index d529ef4f..33138555 100644 --- a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/prefilter/AbstractMatchedPairsFilterNodeModel.java +++ b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/prefilter/AbstractMatchedPairsFilterNodeModel.java @@ -21,7 +21,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicLong; -import org.RDKit.GenericRDKitException; import org.RDKit.MolSanitizeException; import org.RDKit.RDKFuncs; import org.RDKit.ROMol; @@ -55,6 +54,7 @@ import org.rdkit.knime.types.RDKitMolValue; import com.vernalis.exceptions.RowExecutionException; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.mmp.FragmentationTypes; import com.vernalis.knime.mmp.MatchedPairsMultipleCutsNodePlugin; import com.vernalis.knime.mmp.RDKitFragmentationUtils; @@ -361,19 +361,11 @@ protected static ROMol getROMolFromCell(DataCell cell) } catch (MolSanitizeException e) { // MolSanitizeException returns null for #getMessage() throw new RowExecutionException("Error in sanitizing molecule: " - + ((StringValue) cell).getStringValue() + " : " + e.what()); + + ((StringValue) cell).getStringValue() + " : " + + new RDKitRuntimeExceptionHandler(e).getMessage()); } catch (Exception e) { String msg = e.getMessage(); - if (msg == null || "".equals(msg)) { - // Try to do something useful if we have a different RDKit - // Exception - at least try to report the error type! - msg = e.getClass().getSimpleName(); - try { - msg += " : " + ((GenericRDKitException) e).what(); - } catch (Exception e1) { - // Do nothing - } - } + if (msg.equals("Cell is not a recognised molecule type")) { throw new RowExecutionException(msg); } else { diff --git a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/abstrct/AbstractRdkitMatchedPairsMultipleCutsNodeModel.java b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/abstrct/AbstractRdkitMatchedPairsMultipleCutsNodeModel.java index 8138691b..1238e59b 100644 --- a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/abstrct/AbstractRdkitMatchedPairsMultipleCutsNodeModel.java +++ b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/abstrct/AbstractRdkitMatchedPairsMultipleCutsNodeModel.java @@ -17,7 +17,6 @@ import java.io.File; import java.io.IOException; -import org.RDKit.GenericRDKitException; import org.RDKit.MolSanitizeException; import org.RDKit.RDKFuncs; import org.RDKit.ROMol; @@ -49,6 +48,7 @@ import org.rdkit.knime.types.RDKitMolValue; import com.vernalis.exceptions.RowExecutionException; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.mmp.FragmentKey; import com.vernalis.knime.mmp.FragmentKeyMorganFP; import com.vernalis.knime.mmp.FragmentationTypes; @@ -376,20 +376,13 @@ protected ROMol getROMolFromCell(DataCell cell) } } catch (MolSanitizeException e) { // MolSanitizeException returns null for #getMessage() + RDKitRuntimeExceptionHandler e1 = + new RDKitRuntimeExceptionHandler(e); throw new RowExecutionException("Error in sanitizing molecule: " - + ((StringValue) cell).getStringValue() + " : " + e.what()); + + ((StringValue) cell).getStringValue() + " : " + + e1.getMessage(), e1); } catch (Exception e) { String msg = e.getMessage(); - if (msg == null || "".equals(msg)) { - // Try to do something useful if we have a different RDKit - // Exception - at least try to report the error type! - msg = e.getClass().getSimpleName(); - try { - msg += " : " + ((GenericRDKitException) e).what(); - } catch (Exception e1) { - // Do nothing - } - } if (msg.equals("Cell is not a recognised molecule type")) { throw new RowExecutionException(msg); } else { diff --git a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/fragment2/AbstractParallelRdkitMMPFragment3NodeModel.java b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/fragment2/AbstractParallelRdkitMMPFragment3NodeModel.java index 91ba1a6c..1b715a7c 100644 --- a/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/fragment2/AbstractParallelRdkitMMPFragment3NodeModel.java +++ b/com.vernalis.knime.chem.mmp/src-deprecated/com/vernalis/knime/mmp/nodes/rdkit/fragment2/AbstractParallelRdkitMMPFragment3NodeModel.java @@ -23,7 +23,6 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; -import org.RDKit.GenericRDKitException; import org.RDKit.MolSanitizeException; import org.RDKit.RDKFuncs; import org.RDKit.ROMol; @@ -68,6 +67,7 @@ import org.rdkit.knime.types.RDKitMolValue; import com.vernalis.exceptions.RowExecutionException; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.mmp.FragmentationTypes; import com.vernalis.knime.mmp.MatchedPairsMultipleCutsNodePlugin; import com.vernalis.knime.mmp.MulticomponentSmilesFragmentParser; @@ -544,12 +544,15 @@ protected BufferedDataTable[] execute(BufferedDataTable[] inData, * @param stripHsAtEnd * @return */ - private MultiThreadWorker getMultithreadWorker( - final ExecutionContext exec, final int molIdx, final int idIdx, - final long numRows, final BufferedDataContainer dc_0, - final BufferedDataContainer dc_1, final ROMol bondMatch, - final int numCuts, final boolean addHs, final Integer maxNumVarAtm, - final Double minCnstToVarAtmRatio, final boolean stripHsAtEnd) { + private MultiThreadWorker + getMultithreadWorker(final ExecutionContext exec, final int molIdx, + final int idIdx, final long numRows, + final BufferedDataContainer dc_0, + final BufferedDataContainer dc_1, final ROMol bondMatch, + final int numCuts, final boolean addHs, + final Integer maxNumVarAtm, + final Double minCnstToVarAtmRatio, + final boolean stripHsAtEnd) { return new MultiThreadWorker( queueSize, numThreads) { @@ -663,20 +666,13 @@ protected ROMol getROMolFromCell(DataCell cell) } } catch (MolSanitizeException e) { // MolSanitizeException returns null for #getMessage() + RDKitRuntimeExceptionHandler e1 = + new RDKitRuntimeExceptionHandler(e); throw new RowExecutionException("Error in sanitizing molecule: " - + ((StringValue) cell).getStringValue() + " : " + e.what()); + + ((StringValue) cell).getStringValue() + " : " + + e1.getMessage(), e1); } catch (Exception e) { String msg = e.getMessage(); - if (msg == null || "".equals(msg)) { - // Try to do something useful if we have a different RDKit - // Exception - at least try to report the error type! - msg = e.getClass().getSimpleName(); - try { - msg += " : " + ((GenericRDKitException) e).what(); - } catch (Exception e1) { - // Do nothing - } - } if (msg.equals("Cell is not a recognised molecule type")) { throw new RowExecutionException(msg); } else { @@ -797,11 +793,13 @@ protected abstract Set> generateCuttableBondCombos( * @throws CanceledExecutionException * if the user cancels during execution */ - protected Set breakMoleculeAlongBondCombos( - MoleculeFragmentationFactory fragFactory, - Set> bondCombos, boolean prochiralAsChiral, - ExecutionContext exec, NodeLogger logger, boolean verboseLogging) - throws CanceledExecutionException { + protected Set + breakMoleculeAlongBondCombos( + MoleculeFragmentationFactory fragFactory, + Set> bondCombos, + boolean prochiralAsChiral, ExecutionContext exec, + NodeLogger logger, boolean verboseLogging) + throws CanceledExecutionException { int count = 0; Set retVal = new TreeSet<>(); for (Set bondSet : bondCombos) { diff --git a/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragmentors/RWMolFragmentationFactory.java b/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragmentors/RWMolFragmentationFactory.java index 59ba0534..c2e784ad 100644 --- a/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragmentors/RWMolFragmentationFactory.java +++ b/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragmentors/RWMolFragmentationFactory.java @@ -57,6 +57,7 @@ import org.knime.core.data.DataCell; import org.knime.core.data.DataType; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.mmp.ToolkitException; import com.vernalis.knime.mmp.frags.abstrct.AbstractMulticomponentFragmentationParser; import com.vernalis.knime.mmp.frags.abstrct.BondIdentifier; @@ -791,7 +792,7 @@ protected String renderBondSetToSVGString(Color bondColour, "$1" + String.format(Locale.ROOT, "%.2f", alpha)); } } catch (ConformerException e) { - throw new ToolkitException(e.what(), e); + throw new ToolkitException(new RDKitRuntimeExceptionHandler(e)); } finally { if (drawer != null) { drawer.delete(); @@ -1012,7 +1013,7 @@ protected String renderFragmentationToSVGString(Color bondColour, } } catch (ConformerException e) { - throw new ToolkitException(e.what(), e); + throw new ToolkitException(new RDKitRuntimeExceptionHandler(e)); } finally { getGc().cleanupMarkedObjects(localGcWave); } @@ -1063,8 +1064,9 @@ protected void finalize() throws Throwable { } @Override - protected AbstractMulticomponentFragmentationParser createFragmentationParserFromComponents( - Set leafs, RWMol valueComponent, long localGCWave) { + protected AbstractMulticomponentFragmentationParser + createFragmentationParserFromComponents(Set leafs, + RWMol valueComponent, long localGCWave) { try { return new RWMolMulticomponentFragmentationParser(valueComponent, leafs); @@ -1268,9 +1270,12 @@ protected void assignCreatedDblBondGeometry(RWMol component, // bonds RDKFuncs.findPotentialStereoBonds(component, false); } catch (MolSanitizeException e) { + String msg = new RDKitRuntimeExceptionHandler(e).getMessage(); if (verboseLogging) { - logger.info("Problem assigning double bond geometry" - + e.what() == null ? "" : e.what()); + logger.info( + "Problem assigning double bond geometry" + msg == null + ? "" + : msg); } return; } catch (Exception e) { @@ -1348,9 +1353,12 @@ protected void assignAPChirality(RWMol component, long localGCWave) { // Flag possible stereocentres RDKFuncs.assignStereochemistry(component, false, true, true); } catch (MolSanitizeException e) { + String msg = new RDKitRuntimeExceptionHandler(e).getMessage(); if (verboseLogging) { - logger.info("Problem assigning double bond geometry" - + e.what() == null ? "" : e.what()); + logger.info( + "Problem assigning double bond geometry" + msg == null + ? "" + : msg); } return; } catch (Exception e) { diff --git a/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragutils/RWMolFragmentationUtilsFactory.java b/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragutils/RWMolFragmentationUtilsFactory.java index e462865d..a36a2597 100644 --- a/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragutils/RWMolFragmentationUtilsFactory.java +++ b/com.vernalis.knime.chem.mmp/src/com/vernalis/knime/mmp/fragutils/RWMolFragmentationUtilsFactory.java @@ -53,6 +53,7 @@ import org.rdkit.knime.types.RDKitMolValue; import com.vernalis.exceptions.RowExecutionException; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.mmp.MatchedPairsMultipleCutsNodePlugin; import com.vernalis.knime.mmp.MolFormats; import com.vernalis.knime.mmp.ToolkitException; @@ -160,21 +161,14 @@ public RWMol getMolFromCell(DataCell molCell, long rowIndex, } } catch (MolSanitizeException e) { // MolSanitizeException returns null for #getMessage() + RDKitRuntimeExceptionHandler e0 = + new RDKitRuntimeExceptionHandler(e); throw new ToolkitException("Error in sanitizing molecule: " + ((StringValue) molCell).getStringValue() + " : " - + e.what(), e); + + e0.getMessage(), e0); } catch (Exception e) { String msg = e.getMessage(); - if (msg == null || "".equals(msg)) { - // Try to do something useful if we have a different RDKit - // Exception - at least try to report the error type! - msg = e.getClass().getSimpleName(); - try { - msg += " : " + ((GenericRDKitException) e).what(); - } catch (Exception e1) { - // Do nothing - } - } + if (msg.equals("Cell is not a recognised molecule type")) { throw new ToolkitException(msg, e); } else { @@ -272,7 +266,8 @@ public String validateMatcherSmarts(String SMARTS) { matcher = getMatcher(SMARTS); } } catch (GenericRDKitException e) { - return "Unable to generate matcher from SMIRKS - " + e.what(); + return "Unable to generate matcher from SMIRKS - " + + new RDKitRuntimeExceptionHandler(e).getMessage(); } catch (Exception e) { return "Unable to generate matcher from SMIRKS - " + e.getMessage(); } @@ -307,11 +302,12 @@ public String validateMatcherSmarts(String SMARTS) { } @Override - public MoleculeFragmentationFactory2 createFragmentationFactory( - RWMol mol, ROMol bondMatch, boolean stripHsAtEnd, boolean isHAdded, - boolean verboseLog, boolean prochiralAsChiral, Integer maxNumVarAtm, - Double minCnstToVarAtmRatio, int maxLeafCacheSize) - throws ClosedFactoryException, ToolkitException { + public MoleculeFragmentationFactory2 + createFragmentationFactory(RWMol mol, ROMol bondMatch, + boolean stripHsAtEnd, boolean isHAdded, boolean verboseLog, + boolean prochiralAsChiral, Integer maxNumVarAtm, + Double minCnstToVarAtmRatio, int maxLeafCacheSize) + throws ClosedFactoryException, ToolkitException { return new RWMolFragmentationFactory(mol, bondMatch, stripHsAtEnd, isHAdded, verboseLog, prochiralAsChiral, maxNumVarAtm, minCnstToVarAtmRatio, maxLeafCacheSize); @@ -372,11 +368,11 @@ public ChemicalReaction generateReactionFromRSmarts(String rSMARTS, rxn = ChemicalReaction.ReactionFromSmarts(rSMARTS, false); } } catch (ChemicalReactionException e) { - throw new ToolkitException(e.what(), e); + throw new ToolkitException(new RDKitRuntimeExceptionHandler(e)); } catch (ChemicalReactionParserException e) { - throw new ToolkitException(e.what(), e); + throw new ToolkitException(new RDKitRuntimeExceptionHandler(e)); } catch (GenericRDKitException e) { - throw new ToolkitException(e.what(), e); + throw new ToolkitException(new RDKitRuntimeExceptionHandler(e)); } return m_SWIGGC.markForCleanup(rxn, rowIndex); @@ -478,9 +474,9 @@ public DenseBitVector getLeafFingerprint(RWMol mol, int fpLength, ebv = RDKFuncs.getMorganFingerprintAsBitVect(mol, radius, fpLength, null, apIdx, useChirality, useBondTypes); } catch (MolSanitizeException e) { - throw new ToolkitException(e.what(), e); + throw new ToolkitException(new RDKitRuntimeExceptionHandler(e)); } catch (GenericRDKitException e) { - throw new ToolkitException(e.what(), e); + throw new ToolkitException(new RDKitRuntimeExceptionHandler(e)); } finally { apIdx.delete(); if (pair != null) { @@ -525,7 +521,8 @@ public Set getTransformedMoleculesSmiles(RWMol mol, prod.delete(); prods.delete(); reactant.delete(); - throw new ToolkitException(e.what(), e); + throw new ToolkitException( + new RDKitRuntimeExceptionHandler(e)); } RDKFuncs.assignStereochemistry(prodrw, true, true); prodrw.Kekulize(); diff --git a/com.vernalis.knime.chem.pmi/META-INF/MANIFEST.MF b/com.vernalis.knime.chem.pmi/META-INF/MANIFEST.MF index 52487a5b..28c8c47f 100644 --- a/com.vernalis.knime.chem.pmi/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.chem.pmi/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.chem.pmi;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: pmi.jar Bundle-Activator: com.vernalis.knime.chem.pmi.PmiNodePlugin Bundle-Vendor: %Bundle-Vendor @@ -12,9 +12,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.13.0,4.0.0)", org.knime.base;bundle-version="[3.0.0,5.0.0)", org.knime.chem.types;bundle-version="[3.0.0,5.0.0)", org.knime.chem.base;bundle-version="[3.0.0,5.0.0)", - org.rdkit.knime.types;bundle-version="[4.1.0,5.0.0)", + org.rdkit.knime.types;bundle-version="[4.0.0,5.0.0)", com.vernalis.knime.core;bundle-version="[1.6.0,2.0.0)", - com.vernalis.knime.chem.core;bundle-version="[1.23.0,2.0.0)", + com.vernalis.knime.chem.core;bundle-version="[1.27.4,2.0.0)", org.knime.ext.jfreechart;bundle-version="[3.7.0,5.0.0)", com.vernalis.knime.jfcplot.core;bundle-version="[1.23.0,2.0.0)", com.vernalis.knime.plot.jfreechart;bundle-version="[1.23.0,2.0.0)" diff --git a/com.vernalis.knime.chem.pmi/src/com/vernalis/knime/chem/pmi/nodes/confs/rdkitgenerate/RdkitConfgenNodeModel.java b/com.vernalis.knime.chem.pmi/src/com/vernalis/knime/chem/pmi/nodes/confs/rdkitgenerate/RdkitConfgenNodeModel.java index 646c01c1..fd17502e 100644 --- a/com.vernalis.knime.chem.pmi/src/com/vernalis/knime/chem/pmi/nodes/confs/rdkitgenerate/RdkitConfgenNodeModel.java +++ b/com.vernalis.knime.chem.pmi/src/com/vernalis/knime/chem/pmi/nodes/confs/rdkitgenerate/RdkitConfgenNodeModel.java @@ -64,6 +64,7 @@ import org.knime.core.node.defaultnodesettings.SettingsModelString; import com.vernalis.exceptions.RowExecutionException; +import com.vernalis.knime.chem.rdkit.RDKitRuntimeExceptionHandler; import com.vernalis.knime.chem.rdkit.RdkitCompatibleColumnFormats; import com.vernalis.knime.dialog.components.SettingsModelMultilineString; import com.vernalis.knime.misc.ArrayUtils; @@ -514,9 +515,9 @@ public DataCell[] getCells(DataRow row) { } return newCells.toArray(new DataCell[newCells.size()]); } catch (MolSanitizeException e) { - throw new RuntimeException(e.what(), e); + throw new RDKitRuntimeExceptionHandler(e); } catch (GenericRDKitException e) { - throw new RuntimeException(e.what(), e); + throw new RDKitRuntimeExceptionHandler(e); } finally { gc.cleanupMarkedObjects(waveID); } diff --git a/com.vernalis.knime.chem.speedysmiles/META-INF/MANIFEST.MF b/com.vernalis.knime.chem.speedysmiles/META-INF/MANIFEST.MF index 92ebdbc1..18d83424 100644 --- a/com.vernalis.knime.chem.speedysmiles/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.chem.speedysmiles/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.chem.speedysmiles;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: smileshaclargestcomponentdesalt.jar Bundle-Activator: com.vernalis.knime.chem.speedysmiles.SpeedySmilesNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.core/META-INF/MANIFEST.MF b/com.vernalis.knime.core/META-INF/MANIFEST.MF index a9fc20bb..39243be7 100644 --- a/com.vernalis.knime.core/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.core;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: vernaliscore.jar Bundle-Activator: com.vernalis.knime.core.VernalisCoreNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/DialogComponentIntRange.java b/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/DialogComponentIntRange.java index 56be5e53..9e08ef17 100644 --- a/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/DialogComponentIntRange.java +++ b/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/DialogComponentIntRange.java @@ -1,289 +1,444 @@ -/******************************************************************************* - * Copyright (c) 2017, Vernalis (R&D) Ltd - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License, Version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see - ******************************************************************************/ -package com.vernalis.knime.dialog.components; - -import java.text.ParseException; - -import javax.swing.JComponent; -import javax.swing.JFormattedTextField; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; -import javax.swing.JSpinner.DefaultEditor; -import javax.swing.SpinnerNumberModel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import org.knime.core.node.InvalidSettingsException; -import org.knime.core.node.NotConfigurableException; -import org.knime.core.node.defaultnodesettings.DialogComponent; -import org.knime.core.node.defaultnodesettings.SettingsModelDoubleRange; -import org.knime.core.node.port.PortObjectSpec; - -/** - * Allows the user to enter an int number range. It shows two spinners labelled - * "min=" and "max=" which expect each an int. The component requires a - * SettingsModelIntegerRange with its constructor, that holds the two values - * entered. - * - * @see SettingsModelDoubleRange - * - * @author s.roughley - */ -public class DialogComponentIntRange extends DialogComponent { - - private final JLabel m_label; - - private final JLabel m_labelMin; - - private final JLabel m_labelMax; - - private final JSpinner m_spinnerMin; - - private final JSpinner m_spinnerMax; - - /** - * Creates two spinner to enter the lower and upper value of the range. - * - * @param model - * stores the double numbers entered - * @param lowerMin - * minimum value to be entered - * @param upperMax - * maximum value to be entered - * @param stepSize - * step size for the spinners - * @param label - * label for this component - */ - public DialogComponentIntRange(final SettingsModelIntegerRange model, final int lowerMin, - final int upperMax, final int stepSize, final String label) { - this(model, lowerMin, upperMax, stepSize, lowerMin, upperMax, stepSize, label); - } - - /** - * Finegrain constructor to specify minimum and maximum values for the lower - * and upper bound and different step sizes for each spinner. - * - * @param model - * stores the double numbers entered - * @param lowerMin - * minimum value for the lower bound spinner - * @param lowerMax - * maximum value for the lower bound spinner - * @param lowerStepSize - * step size for the lower bound spinner - * @param upperMin - * minimum value for the upper bound spinner - * @param upperMax - * maximum value for the upper bound spinner - * @param upperStepSize - * step size for the upper bound spinner - * @param label - * label for this component - */ - public DialogComponentIntRange(final SettingsModelIntegerRange model, final int lowerMin, - final int lowerMax, final int lowerStepSize, final int upperMin, final int upperMax, - final int upperStepSize, final String label) { - super(model); - - model.prependChangeListener(new ChangeListener() { - @Override - public void stateChanged(final ChangeEvent e) { - updateComponent(); - } - }); - - final JPanel myPanel = getComponentPanel(); - m_label = new JLabel(label); - m_labelMin = new JLabel("min="); - m_labelMax = new JLabel("max="); - m_spinnerMin = new JSpinner( - new SpinnerNumberModel(model.getMinRange(), lowerMin, lowerMax, lowerStepSize)); - m_spinnerMin.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(final ChangeEvent arg0) { - updateMinModel(); - } - }); - JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) m_spinnerMin.getEditor(); - editor.getTextField().setColumns(10); - editor.getTextField().setFocusLostBehavior(JFormattedTextField.COMMIT); - m_spinnerMax = new JSpinner( - new SpinnerNumberModel(model.getMaxRange(), upperMin, upperMax, upperStepSize)); - m_spinnerMax.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(final ChangeEvent arg0) { - updateMaxModel(); - } - }); - editor = (JSpinner.DefaultEditor) m_spinnerMax.getEditor(); - editor.getTextField().setColumns(10); - editor.getTextField().setFocusLostBehavior(JFormattedTextField.COMMIT); - myPanel.add(m_label); - myPanel.add(m_labelMin); - myPanel.add(m_spinnerMin); - - myPanel.add(m_labelMax); - myPanel.add(m_spinnerMax); - // call this method to be in sync with the settings model - updateComponent(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void checkConfigurabilityBeforeLoad(final PortObjectSpec[] specs) - throws NotConfigurableException { - // Nothing to check, we don't care about the specs. - } - - /** - * {@inheritDoc} - */ - @Override - protected void setEnabledComponents(final boolean enabled) { - m_spinnerMin.setEnabled(enabled); - m_spinnerMax.setEnabled(enabled); - } - - /** - * {@inheritDoc} - */ - @Override - public void setToolTipText(final String text) { - m_spinnerMin.setToolTipText(text); - m_spinnerMax.setToolTipText(text); - } - - /** - * Transfers the value from the spinner into the model. Colors the spinner - * red, if the number is not accepted by the settings model. And throws an - * exception then. - * - */ - private void updateMinModel() { - try { - m_spinnerMin.commitEdit(); - if (getModel() instanceof SettingsModelIntegerRange) { - final SettingsModelIntegerRange model = (SettingsModelIntegerRange) getModel(); - model.setMinRange(((Integer) m_spinnerMin.getValue()).intValue()); - } - } catch (final ParseException e) { - final JComponent editorMin = m_spinnerMin.getEditor(); - if (editorMin instanceof DefaultEditor) { - showError(((DefaultEditor) editorMin).getTextField()); - } - } - } - - private void updateMaxModel() { - try { - m_spinnerMax.commitEdit(); - if (getModel() instanceof SettingsModelIntegerRange) { - final SettingsModelIntegerRange model = (SettingsModelIntegerRange) getModel(); - model.setMaxRange(((Integer) m_spinnerMax.getValue()).intValue()); - } - } catch (final ParseException e) { - final JComponent editorMax = m_spinnerMax.getEditor(); - if (editorMax instanceof DefaultEditor) { - showError(((DefaultEditor) editorMax).getTextField()); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void updateComponent() { - - // clear any possible error indication - JComponent editor = m_spinnerMin.getEditor(); - if (editor instanceof DefaultEditor) { - clearError(((DefaultEditor) editor).getTextField()); - } - editor = m_spinnerMax.getEditor(); - if (editor instanceof DefaultEditor) { - clearError(((DefaultEditor) editor).getTextField()); - } - - // update the spinners - final SettingsModelIntegerRange model = (SettingsModelIntegerRange) getModel(); - final int valMin = ((Integer) m_spinnerMin.getValue()).intValue(); - if (valMin != model.getMinRange()) { - m_spinnerMin.setValue(new Integer(model.getMinRange())); - } - final int valMax = ((Integer) m_spinnerMax.getValue()).intValue(); - if (valMax != model.getMaxRange()) { - m_spinnerMax.setValue(new Integer(model.getMaxRange())); - } - - // update enable status - setEnabledComponents(model.isEnabled()); - } - - /** - * {@inheritDoc} - */ - @Override - protected void validateSettingsBeforeSave() throws InvalidSettingsException { - final SettingsModelIntegerRange model = (SettingsModelIntegerRange) getModel(); - int newMin; - int newMax; - // try to commit Minimum - try { - m_spinnerMin.commitEdit(); - newMin = ((Integer) m_spinnerMin.getValue()).intValue(); - } catch (final ParseException e) { - final JComponent editor = m_spinnerMin.getEditor(); - if (editor instanceof DefaultEditor) { - showError(((DefaultEditor) editor).getTextField()); - } - String errMsg = "Invalid number format. "; - errMsg += "Please enter a valid minimum."; - throw new InvalidSettingsException(errMsg); - } - // try to commit Maximum - try { - m_spinnerMax.commitEdit(); - newMax = ((Integer) m_spinnerMax.getValue()).intValue(); - } catch (final ParseException e) { - final JComponent editor = m_spinnerMax.getEditor(); - if (editor instanceof DefaultEditor) { - showError(((DefaultEditor) editor).getTextField()); - } - String errMsg = "Invalid number format. "; - errMsg += "Please enter a valid maximum."; - throw new InvalidSettingsException(errMsg); - } - - try { - new SettingsModelIntegerRange(model.getConfigName(), newMin, newMax); - } catch (final IllegalArgumentException iae) { - JComponent editor = m_spinnerMax.getEditor(); - if (editor instanceof DefaultEditor) { - showError(((DefaultEditor) editor).getTextField()); - } - editor = m_spinnerMin.getEditor(); - if (editor instanceof DefaultEditor) { - showError(((DefaultEditor) editor).getTextField()); - } - throw new InvalidSettingsException(iae.getMessage()); - } - } - -} +/******************************************************************************* + * Copyright (c) 2017, Vernalis (R&D) Ltd + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, Version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + ******************************************************************************/ +package com.vernalis.knime.dialog.components; + +import java.awt.Dimension; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.knime.core.node.InvalidSettingsException; +import org.knime.core.node.NotConfigurableException; +import org.knime.core.node.defaultnodesettings.DialogComponent; +import org.knime.core.node.defaultnodesettings.SettingsModelDoubleRange; +import org.knime.core.node.port.PortObjectSpec; + +/** + * Allows the user to enter an int number range. It shows two spinners labelled + * "min=" and "max=" which expect each an int. The component requires a + * SettingsModelIntegerRange with its constructor, that holds the two values + * entered. + * + * @see SettingsModelDoubleRange + * + * @author s.roughley + */ +public class DialogComponentIntRange extends DialogComponent { + + private static class RangeDialog extends JPanel { + + /** + * + */ + private static final long serialVersionUID = 5415477367833315706L; + private final JLabel label; + private final JLabel minLabel, maxLabel; + private final JSpinner minSpinner, maxSpinner; + + public RangeDialog(String label, int min, int max, int minMin, + int minStepSize, int minMax, int maxMin, int maxStepSize, + int maxMax) { + if (min > max) { + throw new IllegalArgumentException("Min > max!"); + } + this.label = new JLabel(label); + this.minLabel = new JLabel("min="); + this.maxLabel = new JLabel("max="); + this.minSpinner = new JSpinner( + new SpinnerNumberModel(min, minMin, minMax, minStepSize)); + this.maxSpinner = new JSpinner( + new SpinnerNumberModel(max, maxMin, maxMax, maxStepSize)); + + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setMinimumSize(new Dimension(400, 60)); + + Box box = Box.createHorizontalBox(); + box.add(this.label); + box.add(Box.createHorizontalStrut(15)); + box.add(minLabel); + box.add(Box.createHorizontalStrut(5)); + box.add(minSpinner); + box.add(Box.createHorizontalStrut(10)); + box.add(maxLabel); + box.add(Box.createHorizontalStrut(5)); + box.add(maxSpinner); + add(box); + add(Box.createVerticalStrut(10)); + } + + int getMin() { + return ((Integer) minSpinner.getValue()).intValue(); + } + + int getMax() { + return ((Integer) maxSpinner.getValue()).intValue(); + } + + void setMin(int min) { + if (min <= getMax()) { + minSpinner.setValue(Integer.valueOf(min)); + } + + } + + void setMax(int max) { + if (max >= getMin()) { + maxSpinner.setValue(Integer.valueOf(max)); + } + } + + void setRange(int min, int max) { + if (min <= max) { + minSpinner.setValue(Integer.valueOf(min)); + maxSpinner.setValue(Integer.valueOf(max)); + } + } + + /* + * (non-Javadoc) + * + * @see javax.swing.JComponent#setEnabled(boolean) + */ + @Override + public void setEnabled(boolean enabled) { + label.setEnabled(enabled); + minLabel.setEnabled(enabled); + maxLabel.setEnabled(enabled); + minSpinner.setEnabled(enabled); + maxSpinner.setEnabled(enabled); + } + + /* + * (non-Javadoc) + * + * @see javax.swing.JComponent#setEnabled(boolean) + */ + @Override + public void setToolTipText(String tooltip) { + label.setToolTipText(tooltip); + minLabel.setToolTipText(tooltip); + maxLabel.setToolTipText(tooltip); + minSpinner.setToolTipText(tooltip); + maxSpinner.setToolTipText(tooltip); + } + } + + // private final JLabel m_label; + // + // private final JLabel m_labelMin; + // + // private final JLabel m_labelMax; + // + // private final JSpinner m_spinnerMin; + // + // private final JSpinner m_spinnerMax; + private final RangeDialog rangeDialog; + + /** + * Creates two spinner to enter the lower and upper value of the range. + * + * @param model + * stores the double numbers entered + * @param lowerMin + * minimum value to be entered + * @param upperMax + * maximum value to be entered + * @param stepSize + * step size for the spinners + * @param label + * label for this component + */ + public DialogComponentIntRange(final SettingsModelIntegerRange model, + final int lowerMin, final int upperMax, final int stepSize, + final String label) { + this(model, lowerMin, upperMax, stepSize, lowerMin, upperMax, stepSize, + label); + } + + /** + * Finegrain constructor to specify minimum and maximum values for the lower + * and upper bound and different step sizes for each spinner. + * + * @param model + * stores the double numbers entered + * @param lowerMin + * minimum value for the lower bound spinner + * @param lowerMax + * maximum value for the lower bound spinner + * @param lowerStepSize + * step size for the lower bound spinner + * @param upperMin + * minimum value for the upper bound spinner + * @param upperMax + * maximum value for the upper bound spinner + * @param upperStepSize + * step size for the upper bound spinner + * @param label + * label for this component + */ + public DialogComponentIntRange(final SettingsModelIntegerRange model, + final int lowerMin, final int lowerMax, final int lowerStepSize, + final int upperMin, final int upperMax, final int upperStepSize, + final String label) { + super(model); + + // final JPanel myPanel = getComponentPanel(); + // m_label = new JLabel(label); + // m_labelMin = new JLabel("min="); + // m_labelMax = new JLabel("max="); + // m_spinnerMin = new JSpinner(new + // SpinnerNumberModel(model.getMinRange(), + // lowerMin, lowerMax, lowerStepSize)); + // JSpinner.DefaultEditor editor = + // (JSpinner.DefaultEditor) m_spinnerMin.getEditor(); + // editor.getTextField().setColumns(10); + // editor.getTextField().setFocusLostBehavior(JFormattedTextField.COMMIT); + // m_spinnerMin.addChangeListener(new ChangeListener() { + // + // @Override + // public void stateChanged(final ChangeEvent arg0) { + // updateMinModel(); + // } + // }); + // + // m_spinnerMax = new JSpinner(new + // SpinnerNumberModel(model.getMaxRange(), + // upperMin, upperMax, upperStepSize)); + // editor = (JSpinner.DefaultEditor) m_spinnerMax.getEditor(); + // editor.getTextField().setColumns(10); + // editor.getTextField().setFocusLostBehavior(JFormattedTextField.COMMIT); + // m_spinnerMax.addChangeListener(new ChangeListener() { + // + // @Override + // public void stateChanged(final ChangeEvent arg0) { + // updateMaxModel(); + // } + // }); + // + // myPanel.add(m_label); + // myPanel.add(m_labelMin); + // myPanel.add(m_spinnerMin); + // + // myPanel.add(m_labelMax); + // myPanel.add(m_spinnerMax); + + // model.prependChangeListener(new ChangeListener() { + // + // @Override + // public void stateChanged(final ChangeEvent e) { + // updateComponent(); + // } + // }); + // + // // call this method to be in sync with the settings model + // updateComponent(); + rangeDialog = new RangeDialog(label, model.getMinRange(), + model.getMaxRange(), lowerMin, lowerStepSize, lowerMax, + upperMin, upperStepSize, upperMax); + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + // panel.setBorder(BorderFactory + // .createTitledBorder(BorderFactory.createEtchedBorder(), label)); + panel.add(rangeDialog); + getComponentPanel().add(panel); + + model.prependChangeListener(new ChangeListener() { + + @Override + public void stateChanged(final ChangeEvent e) { + updateComponent(); + } + }); + + // call this method to be in sync with the settings model + updateComponent(); + + } + + /** + * {@inheritDoc} + */ + @Override + protected void checkConfigurabilityBeforeLoad(final PortObjectSpec[] specs) + throws NotConfigurableException { + // Nothing to check, we don't care about the specs. + } + + /** + * {@inheritDoc} + */ + @Override + protected void setEnabledComponents(final boolean enabled) { + rangeDialog.setEnabled(enabled); + // m_spinnerMin.setEnabled(enabled); + // m_spinnerMax.setEnabled(enabled); + } + + /** + * {@inheritDoc} + */ + @Override + public void setToolTipText(final String text) { + rangeDialog.setToolTipText(text); + // m_spinnerMin.setToolTipText(text); + // m_spinnerMax.setToolTipText(text); + } + + // /** + // * Transfers the value from the spinner into the model. Colors the spinner + // * red, if the number is not accepted by the settings model. And throws an + // * exception then. + // * + // */ + // private void updateMinModel() { + // try { + // m_spinnerMin.commitEdit(); + // if (getModel() instanceof SettingsModelIntegerRange) { + // final SettingsModelIntegerRange model = + // (SettingsModelIntegerRange) getModel(); + // model.setMinRange( + // ((Integer) m_spinnerMin.getValue()).intValue()); + // } + // } catch (final ParseException e) { + // final JComponent editorMin = m_spinnerMin.getEditor(); + // if (editorMin instanceof DefaultEditor) { + // showError(((DefaultEditor) editorMin).getTextField()); + // } + // } + // } + // + // private void updateMaxModel() { + // try { + // m_spinnerMax.commitEdit(); + // if (getModel() instanceof SettingsModelIntegerRange) { + // final SettingsModelIntegerRange model = + // (SettingsModelIntegerRange) getModel(); + // model.setMaxRange( + // ((Integer) m_spinnerMax.getValue()).intValue()); + // } + // } catch (final ParseException e) { + // final JComponent editorMax = m_spinnerMax.getEditor(); + // if (editorMax instanceof DefaultEditor) { + // showError(((DefaultEditor) editorMax).getTextField()); + // } + // } + // } + + /** + * {@inheritDoc} + */ + @Override + protected void updateComponent() { + + // // clear any possible error indication + // JComponent editor = m_spinnerMin.getEditor(); + // if (editor instanceof DefaultEditor) { + // clearError(((DefaultEditor) editor).getTextField()); + // } + // editor = m_spinnerMax.getEditor(); + // if (editor instanceof DefaultEditor) { + // clearError(((DefaultEditor) editor).getTextField()); + // } + // + // // update the spinners + // final SettingsModelIntegerRange model = + // (SettingsModelIntegerRange) getModel(); + // try { + // m_spinnerMin.commitEdit(); + // m_spinnerMax.commitEdit(); + // + // final int valMin = ((Integer) m_spinnerMin.getValue()).intValue(); + // if (valMin != model.getMinRange()) { + // m_spinnerMin.setValue(Integer.valueOf(model.getMinRange())); + // } + // final int valMax = ((Integer) m_spinnerMax.getValue()).intValue(); + // if (valMax != model.getMaxRange()) { + // m_spinnerMax.setValue(Integer.valueOf(model.getMaxRange())); + // } + // } catch (ParseException e) { + // m_spinnerMin.setValue(model.getMinRange()); + // m_spinnerMax.setValue(model.getMaxRange()); + // } + + final SettingsModelIntegerRange model = + (SettingsModelIntegerRange) getModel(); + rangeDialog.setRange(model.getMinRange(), model.getMaxRange()); + + // update enable status + setEnabledComponents(model.isEnabled()); + } + + /** + * {@inheritDoc} + */ + @Override + protected void validateSettingsBeforeSave() + throws InvalidSettingsException { + final SettingsModelIntegerRange model = + (SettingsModelIntegerRange) getModel(); + model.setMinRange(rangeDialog.getMin()); + model.setMaxRange(rangeDialog.getMax()); + // int newMin; + // int newMax; + // // try to commit Minimum + // try { + // m_spinnerMin.commitEdit(); + // newMin = ((Integer) m_spinnerMin.getValue()).intValue(); + // } catch (final ParseException e) { + // final JComponent editor = m_spinnerMin.getEditor(); + // if (editor instanceof DefaultEditor) { + // showError(((DefaultEditor) editor).getTextField()); + // } + // String errMsg = "Invalid number format. "; + // errMsg += "Please enter a valid minimum."; + // throw new InvalidSettingsException(errMsg); + // } + // // try to commit Maximum + // try { + // m_spinnerMax.commitEdit(); + // newMax = ((Integer) m_spinnerMax.getValue()).intValue(); + // } catch (final ParseException e) { + // final JComponent editor = m_spinnerMax.getEditor(); + // if (editor instanceof DefaultEditor) { + // showError(((DefaultEditor) editor).getTextField()); + // } + // String errMsg = "Invalid number format. "; + // errMsg += "Please enter a valid maximum."; + // throw new InvalidSettingsException(errMsg); + // } + // + // try { + // new SettingsModelIntegerRange(model.getConfigName(), newMin, + // newMax); + // } catch (final IllegalArgumentException iae) { + // JComponent editor = m_spinnerMax.getEditor(); + // if (editor instanceof DefaultEditor) { + // showError(((DefaultEditor) editor).getTextField()); + // } + // editor = m_spinnerMin.getEditor(); + // if (editor instanceof DefaultEditor) { + // showError(((DefaultEditor) editor).getTextField()); + // } + // throw new InvalidSettingsException(iae.getMessage()); + // } + } + +} diff --git a/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/SettingsModelStringArrayFlowVarReplacable.java b/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/SettingsModelStringArrayFlowVarReplacable.java index 6917dfd5..ace5cf7e 100644 --- a/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/SettingsModelStringArrayFlowVarReplacable.java +++ b/com.vernalis.knime.core/src/com/vernalis/knime/dialog/components/SettingsModelStringArrayFlowVarReplacable.java @@ -1,157 +1,186 @@ -/******************************************************************************* - * Copyright (c) 2016, Vernalis (R&D) Ltd - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License, Version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see - ******************************************************************************/ -package com.vernalis.knime.dialog.components; - -import org.knime.core.node.defaultnodesettings.SettingsModelFlowVariableCompatible; -import org.knime.core.node.defaultnodesettings.SettingsModelString; - -/** - * A SettingsModel which can be used to supply a String Array directly to / from - * a single flow variable. - *

- * The array is serialised as a string by concatenating all entries with a - * deliminator. This is the value which is then stored, enabling e.g. lists of - * files to be passed as an array, but supplied from a single Flow Variable. - *

- *

- * NB It is important to ensure that the chosen deliminator does not - * appear in any of the array entries. If it does, then the array will become - * corrupted on serialisation. It is also important to note that the deliminator - * must be a valid regex, as it is used during deserialisation in - * {@link String#split(String)} - * - * @author "Steve Roughley knime@vernalis.com" - * - */ -public class SettingsModelStringArrayFlowVarReplacable extends - SettingsModelString implements SettingsModelFlowVariableCompatible { - - /** The default deliminator */ - public static final String DELIMINATOR = ";"; - - protected String m_deliminator; - - /** - * Default constructor, where the settings model is created with the given - * parameters, and the default deliminator - * {@link SettingsModelStringArrayFlowVarReplacable#DELIMINATOR} is used. If - * an alternative deliminator is required, then - * {@link #SettingsModelStringArrayFlowVarReplacable(String, String[], String)} - * should be used. - * - * @param configName - * The name of the settings model configuration - * @param defaultValue - * The default value for the settings model. - */ - public SettingsModelStringArrayFlowVarReplacable(String configName, - String[] defaultValue) { - super(configName, ""); - m_deliminator = DELIMINATOR; - setStringArrayValue(defaultValue); - } - - /** - * Constructor in which a non-default string deliminator is supplied. If the - * default deliminator is used, then - * {@link #SettingsModelStringArrayFlowVarReplacable(String, String[])} - * should be used. - * - * @param configName - * The name of the settings model configuration - * @param defaultValue - * The default value for the settings model. - * @param deliminator - * A deliminator to separate items in the array when the array is - * serialised to / from a flow variable string. This character - * sequence must not appear in the possible array entries, else - * corruption will result - */ - public SettingsModelStringArrayFlowVarReplacable(String configName, - String[] defaultValue, String deliminator) { - super(configName, ""); - m_deliminator = deliminator; - setStringArrayValue(defaultValue); - } - - /** - * @return The stored values array. May return {@code null} - */ - public String[] getStringArrayValue() { - String stringValue = super.getStringValue(); - if (stringValue == null) { - return null; - } - if ("".equals(stringValue)) { - return new String[0]; - } - String[] retVal; - if (stringValue.indexOf(m_deliminator) >= 0) { - retVal = stringValue.split(m_deliminator); - for (int i = 0; i < retVal.length; i++) { - retVal[i] = retVal[i].trim(); - } - } else { - // Only a single value - retVal = new String[1]; - retVal[0] = stringValue.trim(); - } - return retVal; - } - - /** - * Set the value of the stored array - * - * @param values - * The values to be used (can be {@code null}) - */ - public void setStringArrayValue(String[] values) { - String stringVal; - if (values == null) { - stringVal = null; - } else if (values.length == 0) { - stringVal = ""; - } else { - // We have at least one value... - StringBuilder retVal = new StringBuilder(values[0]); - for (int i = 1; i < values.length; i++) { - retVal.append(m_deliminator).append(values[i]); - } - stringVal = retVal.toString(); - } - super.setStringValue(stringVal); - } - - /* - * (non-Javadoc) - * - * @see - * org.knime.core.node.defaultnodesettings.SettingsModelString#getModelTypeID - * () - */ - @Override - protected String getModelTypeID() { - return "SMID_StringArray_FlowVarReplacable"; - } - - /** - * @return The deliminator used for serialization of Arrays to Strings and - * vice versa - */ - public String getDeliminator() { - return m_deliminator; - } - -} +/******************************************************************************* + * Copyright (c) 2016, Vernalis (R&D) Ltd + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, Version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + ******************************************************************************/ +package com.vernalis.knime.dialog.components; + +import javax.swing.event.ChangeListener; + +import org.knime.core.node.defaultnodesettings.SettingsModelFlowVariableCompatible; +import org.knime.core.node.defaultnodesettings.SettingsModelString; + +/** + * A SettingsModel which can be used to supply a String Array directly to / from + * a single flow variable. + *

+ * The array is serialised as a string by concatenating all entries with a + * deliminator. This is the value which is then stored, enabling e.g. lists of + * files to be passed as an array, but supplied from a single Flow Variable. + *

+ *

+ * NB It is important to ensure that the chosen deliminator does not + * appear in any of the array entries. If it does, then the array will become + * corrupted on serialisation. It is also important to note that the deliminator + * must be a valid regex, as it is used during deserialisation in + * {@link String#split(String)} + * + * @author "Steve Roughley knime@vernalis.com" + * + */ +public class SettingsModelStringArrayFlowVarReplacable extends + SettingsModelString implements SettingsModelFlowVariableCompatible { + + /** The default deliminator */ + public static final String DELIMINATOR = ";"; + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + protected String m_deliminator; + + /** + * Default constructor, where the settings model is created with the given + * parameters, and the default deliminator + * {@link SettingsModelStringArrayFlowVarReplacable#DELIMINATOR} is used. If + * an alternative deliminator is required, then + * {@link #SettingsModelStringArrayFlowVarReplacable(String, String[], String)} + * should be used. + * + * @param configName + * The name of the settings model configuration + * @param defaultValue + * The default value for the settings model. + */ + public SettingsModelStringArrayFlowVarReplacable(String configName, + String[] defaultValue) { + super(configName, ""); + m_deliminator = DELIMINATOR; + setStringArrayValue(defaultValue); + } + + /** + * Constructor in which a non-default string deliminator is supplied. If the + * default deliminator is used, then + * {@link #SettingsModelStringArrayFlowVarReplacable(String, String[])} + * should be used. + * + * @param configName + * The name of the settings model configuration + * @param defaultValue + * The default value for the settings model. + * @param deliminator + * A deliminator to separate items in the array when the array is + * serialised to / from a flow variable string. This character + * sequence must not appear in the possible array entries, else + * corruption will result + */ + public SettingsModelStringArrayFlowVarReplacable(String configName, + String[] defaultValue, String deliminator) { + super(configName, ""); + m_deliminator = deliminator; + setStringArrayValue(defaultValue); + } + + /** + * @return The stored values array. May return {@code null} + */ + public String[] getStringArrayValue() { + String stringValue = super.getStringValue(); + if (stringValue == null) { + return null; + } + if (stringValue.isEmpty()) { + return EMPTY_STRING_ARRAY; + } + String[] retVal; + if (stringValue.indexOf(m_deliminator) >= 0) { + retVal = stringValue.split(m_deliminator); + for (int i = 0; i < retVal.length; i++) { + retVal[i] = retVal[i].trim(); + } + } else { + // Only a single value + retVal = new String[1]; + retVal[0] = stringValue.trim(); + } + return retVal; + } + + public String[] getStringArrayValueNeverNull() { + if (super.getStringValue() == null) { + return EMPTY_STRING_ARRAY; + } + return getStringArrayValue(); + } + + /** + * Set the value of the stored array + * + * @param values + * The values to be used (can be {@code null}) + */ + public void setStringArrayValue(String[] values) { + String stringVal; + if (values == null) { + stringVal = null; + } else if (values.length == 0) { + stringVal = ""; + } else { + // We have at least one value... + StringBuilder retVal = new StringBuilder(values[0]); + for (int i = 1; i < values.length; i++) { + retVal.append(m_deliminator).append(values[i]); + } + stringVal = retVal.toString(); + } + super.setStringValue(stringVal); + } + + /** + * Convenience method to set the value store to an empty string array + */ + public void setEmptyStringArray() { + setStringArrayValue(EMPTY_STRING_ARRAY); + } + + /* + * (non-Javadoc) + * + * @see org.knime.core.node.defaultnodesettings.SettingsModelString# + * getModelTypeID () + */ + @Override + protected String getModelTypeID() { + return "SMID_StringArray_FlowVarReplacable"; + } + + /** + * @return The deliminator used for serialization of Arrays to Strings and + * vice versa + */ + public String getDeliminator() { + return m_deliminator; + } + + /* + * (non-Javadoc) + * + * @see org.knime.core.node.defaultnodesettings.SettingsModel# + * prependChangeListener(javax.swing.event.ChangeListener) + */ + @Override + protected void prependChangeListener(ChangeListener l) { + // Make it visible to custom components + super.prependChangeListener(l); + } + +} diff --git a/com.vernalis.knime.core/src/com/vernalis/knime/misc/ArrayUtils.java b/com.vernalis.knime.core/src/com/vernalis/knime/misc/ArrayUtils.java index af8c5c88..85ceb401 100644 --- a/com.vernalis.knime.core/src/com/vernalis/knime/misc/ArrayUtils.java +++ b/com.vernalis.knime.core/src/com/vernalis/knime/misc/ArrayUtils.java @@ -1,1050 +1,1118 @@ -/******************************************************************************* - * Copyright (c) 2018,2020 Vernalis (R&D) Ltd - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License, Version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see - ******************************************************************************/ -package com.vernalis.knime.misc; - -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.function.Supplier; - -/** - * A utility class of static helper functions relating to Arrays. Many of these - * wrap methods from {@link Arrays} - * - * @author S.Roughley - * - */ -public class ArrayUtils { - - private ArrayUtils() { - // Utility Class - Do not Instantiate - } - - /** - * Wrapper for {@link Arrays#fill(long[], long)}, returning the filled - * array, replaces the following: - * - *

-	 *     long[] arr = new long[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     long[] arr = new long[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static long[] fill(long[] a, long val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(int[], int)}, returning the filled array, - * replaces the following: - * - *
-	 *     int[] arr = new int[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     int[] arr = new int[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static int[] fill(int[] a, int val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(short[], short)}, returning the filled - * array, replaces the following: - * - *
-	 *     short[] arr = new short[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     short[] arr = new short[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static short[] fill(short[] a, short val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(char[], char)}, returning the filled - * array, replaces the following: - * - *
-	 *     char[] arr = new char[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     char[] arr = new char[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static char[] fill(char[] a, char val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(byte[], byte)}, returning the filled - * array, replaces the following: - * - *
-	 *     byte[] arr = new byte[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     byte[] arr = new byte[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static byte[] fill(byte[] a, byte val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(boolean[], boolean)}, returning the filled - * array, replaces the following: - * - *
-	 *     boolean[] arr = new boolean[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     boolean[] arr = new boolean[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static boolean[] fill(boolean[] a, boolean val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(float[], float)}, returning the filled - * array, replaces the following: - * - *
-	 *     float[] arr = new float[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     float[] arr = new float[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static float[] fill(float[] a, float val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(double[], double)}, returning the filled - * array, replaces the following: - * - *
-	 *     double[] arr = new double[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     double[] arr = new double[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static double[] fill(double[] a, double val) { - Arrays.fill(a, val); - return a; - } - - /** - * Wrapper for {@link Arrays#fill(Object[], Object)}, returning the filled - * array, replaces the following: - * - *
-	 *     SomeType[] arr = new SomeType[3];
-	 *     if (condition) {
-	 *         Arrays.fill(arr, defaultValue);
-	 *         return arr;
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * with - * - *
-	 *     SomeType[] arr = new SomeType[3];
-	 *     if (condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 *     return arr;
-	 * 
- * - * @param a - * The array to fill - * @param val - * The value to fill with - * @return The filled array - */ - public static T[] fill(T[] a, T val) { - Arrays.fill(a, val); - return a; - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     long[] arr = new long[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static long[] of(long val, int size) { - return fill(new long[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     int[] arr = new int[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static int[] of(int val, int size) { - return fill(new int[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     short[] arr = new short[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static short[] of(short val, int size) { - return fill(new short[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     char[] arr = new char[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static char[] of(char val, int size) { - return fill(new char[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     byte[] arr = new byte[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static byte[] of(byte val, int size) { - return fill(new byte[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     boolean[] arr = new boolean[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static boolean[] of(boolean val, int size) { - return fill(new boolean[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     float[] arr = new float[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static float[] of(float val, int size) { - return fill(new float[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     double[] arr = new double[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array - */ - public static double[] of(double val, int size) { - return fill(new double[size], val); - } - - /** - * Convenience method to return an array of given size, pre-filled with a - * default value. The following code: - * - *
-	 *     if(condition) {
-	 *         return ArrayUtils.of(defaultValue, 7);
-	 *     }
-	 *     ...
-	 * 
- * - * is equivalent to: - * - *
-	 *     SomeType[] arr = new SomeType[7];
-	 *     if(condition) {
-	 *         return ArrayUtils.fill(arr, defaultValue);
-	 *     }
-	 *     ...
-	 * 
- * - * @param val - * The value to fill the array with - * @param size - * The size of the array - * @return A pre-filled array, all containing the same object - * @see #of(Supplier, int) - */ - public static T[] of(T val, int size) { - @SuppressWarnings("unchecked") - final T[] a = (T[]) Array.newInstance(val.getClass(), size); - return fill(a, val); - } - - /** - * A method to return a new, prefilled array, with each position filled by - * an object from a {@link Supplier} - * - * @param supplier - * The object Supplier - * @param size - * The size of the result array - * @return A new, prefilled array - * @see #of(Object, int) - */ - public static T[] of(Supplier supplier, int size) { - final T val = supplier.get(); - @SuppressWarnings("unchecked") - final T[] a = (T[]) Array.newInstance(val.getClass(), size); - a[0] = val; - for (int i = 1; i < a.length; i++) { - a[i] = supplier.get(); - } - return a; - } - - /** - * Wrapper for {@link Arrays#copyOf(long[], int)} to copy whole array - * - *
-	 * long[] a = ...
-	 * ...
-	 * long[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * long[] a = ...
-	 * ...
-	 * long[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static long[] copy(long[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(int[], int)} to copy whole array - * - *
-	 * int[] a = ...
-	 * ...
-	 * int[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * int[] a = ...
-	 * ...
-	 * int[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static int[] copy(int[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(short[], int)} to copy whole array - * - *
-	 * short[] a = ...
-	 * ...
-	 * short[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * short[] a = ...
-	 * ...
-	 * short[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static short[] copy(short[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(char[], int)} to copy whole array - * - *
-	 * char[] a = ...
-	 * ...
-	 * char[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * char[] a = ...
-	 * ...
-	 * char[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static char[] copy(char[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(byte[], int)} to copy whole array - * - *
-	 * byte[] a = ...
-	 * ...
-	 * byte[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * byte[] a = ...
-	 * ...
-	 * byte[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static byte[] copy(byte[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(boolean[], int)} to copy whole array - * - *
-	 * boolean[] a = ...
-	 * ...
-	 * boolean[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * boolean[] a = ...
-	 * ...
-	 * boolean[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static boolean[] copy(boolean[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(long[], int)} to copy whole array - * - *
-	 * float[] a = ...
-	 * ...
-	 * float[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * float[] a = ...
-	 * ...
-	 * float[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static float[] copy(float[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(long[], int)} to copy whole array - * - *
-	 * double[] a = ...
-	 * ...
-	 * double[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * double[] a = ...
-	 * ...
-	 * double[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * @param a - * incoming array - * @return new copied array - */ - public static double[] copy(double[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Wrapper for {@link Arrays#copyOf(Object[], int)} to copy whole array - * - *
-	 * T[] a = ...
-	 * ...
-	 * T[] b = ArrayUtils.copy(a);
-	 * 
- * - * is equivalent to - * - *
-	 * T[] a = ...
-	 * ...
-	 * T[b] = Arrays.copyOf(a, a.length);
-	 * 
- * - * where T is the class of an object - * - * @param a - * incoming array - * @return new copied array - */ - public static T[] copy(T[] a) { - return Arrays.copyOf(a, a.length); - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static long[] removeEntry(long[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final long[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static int[] removeEntry(int[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final int[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static short[] removeEntry(short[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final short[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static char[] removeEntry(char[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final char[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static byte[] removeEntry(byte[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final byte[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static boolean[] removeEntry(boolean[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final boolean[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static float[] removeEntry(float[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final float[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static double[] removeEntry(double[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final double[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } - - /** - * Method to remove an entry from an array and return the new array - * - * @param a The incoming array - * @param index The array to copy - * @return the newly copied array with one fewer elements - */ - public static T[] removeEntry(T[] a, int index) { - if (index < 0 || index >= a.length) { - throw new ArrayIndexOutOfBoundsException(); - } - final T[] retVal = Arrays.copyOf(a, a.length - 1); - if (retVal.length != index) { - System.arraycopy(a, index + 1, retVal, index, retVal.length - index); - } - return retVal; - } -} +/******************************************************************************* + * Copyright (c) 2018,2020 Vernalis (R&D) Ltd + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, Version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + ******************************************************************************/ +package com.vernalis.knime.misc; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * A utility class of static helper functions relating to Arrays. Many of these + * wrap methods from {@link Arrays} + * + * @author S.Roughley + * + */ +public class ArrayUtils { + + private ArrayUtils() { + // Utility Class - Do not Instantiate + } + + /** + * Wrapper for {@link Arrays#fill(long[], long)}, returning the filled + * array, replaces the following: + * + *
+	 *     long[] arr = new long[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     long[] arr = new long[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static long[] fill(long[] a, long val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(int[], int)}, returning the filled array, + * replaces the following: + * + *
+	 *     int[] arr = new int[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     int[] arr = new int[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static int[] fill(int[] a, int val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(short[], short)}, returning the filled + * array, replaces the following: + * + *
+	 *     short[] arr = new short[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     short[] arr = new short[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static short[] fill(short[] a, short val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(char[], char)}, returning the filled + * array, replaces the following: + * + *
+	 *     char[] arr = new char[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     char[] arr = new char[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static char[] fill(char[] a, char val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(byte[], byte)}, returning the filled + * array, replaces the following: + * + *
+	 *     byte[] arr = new byte[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     byte[] arr = new byte[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static byte[] fill(byte[] a, byte val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(boolean[], boolean)}, returning the filled + * array, replaces the following: + * + *
+	 *     boolean[] arr = new boolean[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     boolean[] arr = new boolean[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static boolean[] fill(boolean[] a, boolean val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(float[], float)}, returning the filled + * array, replaces the following: + * + *
+	 *     float[] arr = new float[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     float[] arr = new float[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static float[] fill(float[] a, float val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(double[], double)}, returning the filled + * array, replaces the following: + * + *
+	 *     double[] arr = new double[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     double[] arr = new double[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static double[] fill(double[] a, double val) { + Arrays.fill(a, val); + return a; + } + + /** + * Wrapper for {@link Arrays#fill(Object[], Object)}, returning the filled + * array, replaces the following: + * + *
+	 *     SomeType[] arr = new SomeType[3];
+	 *     if (condition) {
+	 *         Arrays.fill(arr, defaultValue);
+	 *         return arr;
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * with + * + *
+	 *     SomeType[] arr = new SomeType[3];
+	 *     if (condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 *     return arr;
+	 * 
+ * + * @param a + * The array to fill + * @param val + * The value to fill with + * @return The filled array + */ + public static T[] fill(T[] a, T val) { + Arrays.fill(a, val); + return a; + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     long[] arr = new long[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static long[] of(long val, int size) { + return fill(new long[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     int[] arr = new int[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static int[] of(int val, int size) { + return fill(new int[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     short[] arr = new short[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static short[] of(short val, int size) { + return fill(new short[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     char[] arr = new char[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static char[] of(char val, int size) { + return fill(new char[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     byte[] arr = new byte[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static byte[] of(byte val, int size) { + return fill(new byte[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     boolean[] arr = new boolean[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static boolean[] of(boolean val, int size) { + return fill(new boolean[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     float[] arr = new float[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static float[] of(float val, int size) { + return fill(new float[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     double[] arr = new double[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array + */ + public static double[] of(double val, int size) { + return fill(new double[size], val); + } + + /** + * Convenience method to return an array of given size, pre-filled with a + * default value. The following code: + * + *
+	 *     if(condition) {
+	 *         return ArrayUtils.of(defaultValue, 7);
+	 *     }
+	 *     ...
+	 * 
+ * + * is equivalent to: + * + *
+	 *     SomeType[] arr = new SomeType[7];
+	 *     if(condition) {
+	 *         return ArrayUtils.fill(arr, defaultValue);
+	 *     }
+	 *     ...
+	 * 
+ * + * @param val + * The value to fill the array with + * @param size + * The size of the array + * @return A pre-filled array, all containing the same object + * @see #of(Supplier, int) + */ + public static T[] of(T val, int size) { + @SuppressWarnings("unchecked") + final T[] a = (T[]) Array.newInstance(val.getClass(), size); + return fill(a, val); + } + + /** + * A method to return a new, prefilled array, with each position filled by + * an object from a {@link Supplier} + * + * @param supplier + * The object Supplier + * @param size + * The size of the result array + * @return A new, prefilled array + * @see #of(Object, int) + */ + public static T[] of(Supplier supplier, int size) { + final T val = supplier.get(); + @SuppressWarnings("unchecked") + final T[] a = (T[]) Array.newInstance(val.getClass(), size); + a[0] = val; + for (int i = 1; i < a.length; i++) { + a[i] = supplier.get(); + } + return a; + } + + /** + * Method to remove any {@code null} elements from an array + * + * @param a + * The array + * @return The array without {@code null}s + */ + public static T[] trimNulls(T[] a) { + List l = Arrays.stream(a).filter(t -> t != null) + .collect(Collectors.toList()); + @SuppressWarnings("unchecked") + T[] retVal = (T[]) Array.newInstance(a.getClass().getComponentType(), + l.size()); + return l.toArray(retVal); + } + + /** + * Returns a copy of the bit-reverse permuted input array (See + * https://en.wikipedia.org/wiki/Bit-reversal_permutation), which is useful + * in e.g. Fast-Fourier Transforms + * + * @param a + * The array to permute + * @return A permuted copy + */ + public static T[] bitReversePermute(T[] a) { + if (Integer.highestOneBit(a.length) != a.length) { + throw new IllegalArgumentException("Array must be of length 2^k"); + } + @SuppressWarnings("unchecked") + final T[] r = (T[]) Array.newInstance(a.getClass().getComponentType(), + a.length); + int shift = Integer.numberOfLeadingZeros(a.length) + 1; + for (int i = 0; i < a.length; i++) { + r[Integer.reverse(i) >>> shift] = a[i]; + } + return r; + } + + /** + * Wrapper for {@link Arrays#copyOf(long[], int)} to copy whole array + * + *
+	 * long[] a = ...
+	 * ...
+	 * long[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * long[] a = ...
+	 * ...
+	 * long[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static long[] copy(long[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(int[], int)} to copy whole array + * + *
+	 * int[] a = ...
+	 * ...
+	 * int[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * int[] a = ...
+	 * ...
+	 * int[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static int[] copy(int[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(short[], int)} to copy whole array + * + *
+	 * short[] a = ...
+	 * ...
+	 * short[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * short[] a = ...
+	 * ...
+	 * short[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static short[] copy(short[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(char[], int)} to copy whole array + * + *
+	 * char[] a = ...
+	 * ...
+	 * char[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * char[] a = ...
+	 * ...
+	 * char[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static char[] copy(char[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(byte[], int)} to copy whole array + * + *
+	 * byte[] a = ...
+	 * ...
+	 * byte[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * byte[] a = ...
+	 * ...
+	 * byte[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static byte[] copy(byte[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(boolean[], int)} to copy whole array + * + *
+	 * boolean[] a = ...
+	 * ...
+	 * boolean[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * boolean[] a = ...
+	 * ...
+	 * boolean[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static boolean[] copy(boolean[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(long[], int)} to copy whole array + * + *
+	 * float[] a = ...
+	 * ...
+	 * float[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * float[] a = ...
+	 * ...
+	 * float[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static float[] copy(float[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(long[], int)} to copy whole array + * + *
+	 * double[] a = ...
+	 * ...
+	 * double[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * double[] a = ...
+	 * ...
+	 * double[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * @param a + * incoming array + * @return new copied array + */ + public static double[] copy(double[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Wrapper for {@link Arrays#copyOf(Object[], int)} to copy whole array + * + *
+	 * T[] a = ...
+	 * ...
+	 * T[] b = ArrayUtils.copy(a);
+	 * 
+ * + * is equivalent to + * + *
+	 * T[] a = ...
+	 * ...
+	 * T[b] = Arrays.copyOf(a, a.length);
+	 * 
+ * + * where T is the class of an object + * + * @param a + * incoming array + * @return new copied array + */ + public static T[] copy(T[] a) { + return Arrays.copyOf(a, a.length); + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static long[] removeEntry(long[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final long[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static int[] removeEntry(int[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final int[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static short[] removeEntry(short[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final short[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static char[] removeEntry(char[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final char[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static byte[] removeEntry(byte[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final byte[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static boolean[] removeEntry(boolean[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final boolean[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static float[] removeEntry(float[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final float[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static double[] removeEntry(double[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final double[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } + + /** + * Method to remove an entry from an array and return the new array + * + * @param a + * The incoming array + * @param index + * The array to copy + * @return the newly copied array with one fewer elements + */ + public static T[] removeEntry(T[] a, int index) { + if (index < 0 || index >= a.length) { + throw new ArrayIndexOutOfBoundsException(); + } + final T[] retVal = Arrays.copyOf(a, a.length - 1); + if (retVal.length != index) { + System.arraycopy(a, index + 1, retVal, index, + retVal.length - index); + } + return retVal; + } +} diff --git a/com.vernalis.knime.core/src/com/vernalis/knime/misc/EitherOr.java b/com.vernalis.knime.core/src/com/vernalis/knime/misc/EitherOr.java index 354c3153..68dab36d 100644 --- a/com.vernalis.knime.core/src/com/vernalis/knime/misc/EitherOr.java +++ b/com.vernalis.knime.core/src/com/vernalis/knime/misc/EitherOr.java @@ -1,197 +1,199 @@ -/******************************************************************************* - * Copyright (c) 2017, Vernalis (R&D) Ltd - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License, Version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see - ******************************************************************************/ -package com.vernalis.knime.misc; - -import java.util.NoSuchElementException; -import java.util.Objects; - -/** - * A class allowing one of two different types to be provided as an argument for - * a method. Only one type is ever present. An empty instance is also possible. - * This is loosely based on the Java 1.8 'Optional' class - * - * @author s.roughley - * - * @param - * The 'left' type parameter - * @param - * The 'right' type parameter - */ -public final class EitherOr { - private final T left; - private final U right; - - private EitherOr(T left, U right) { - this.left = left; - this.right = right; - } - - /** - * Empty Instance - */ - private static final EitherOr EMPTY = new EitherOr<>(null, null); - - /** - * Create a 'left' object - * - * @param value - * The value to hold (non-null) - * @return A 'left' container object - * @throws NullPointerException - * if a null value was supplied - */ - public static EitherOr ofLeft(T value) throws NullPointerException { - return new EitherOr<>(Objects.requireNonNull(value), null); - } - - /** - * Create a 'right' object - * - * @param value - * The value to hold (non-null) - * @return A 'right' container object - * @throws NullPointerException - * if a null value was supplied - */ - public static EitherOr ofRight(U value) { - return new EitherOr<>(null, Objects.requireNonNull(value)); - } - - /** - * @return An empty object (containing no values) Note - use - * {@link #isEmpty()} or {@link #isPresent()} to check for - * 'emptiness' - */ - public static EitherOr empty() { - @SuppressWarnings("unchecked") - EitherOr retVal = (EitherOr) EMPTY; - return retVal; - } - - /** - * @return true if the object is a 'left' container - */ - public boolean isLeft() { - return left != null; - } - - /** - * @return true if the object is a 'right' container - */ - public boolean isRight() { - return right != null; - } - - /** - * @return true if the object contains neither left or right - * values - */ - public boolean isEmpty() { - return !isPresent(); - } - - /** - * @return true if the object contains either a left or right - * value - */ - public boolean isPresent() { - return isLeft() || isRight(); - } - - /** - * @return The non-null left value - * @throws NoSuchElementException - * if there is no stored left value - */ - public T getLeft() throws NoSuchElementException { - if (!isLeft()) { - throw new NoSuchElementException("No left value present"); - } - return left; - } - - /** - * @return The non-null right value - * @throws NoSuchElementException - * if there is no stored right value - */ - public U getRight() throws NoSuchElementException { - if (!isRight()) { - throw new NoSuchElementException("No left value present"); - } - return right; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((left == null) ? 0 : left.hashCode()); - result = prime * result + ((right == null) ? 0 : right.hashCode()); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof EitherOr)) { - return false; - } - EitherOr other = (EitherOr) obj; - if (left == null) { - if (other.left != null) { - return false; - } - } else if (!left.equals(other.left)) { - return false; - } - if (right == null) { - if (other.right != null) { - return false; - } - } else if (!right.equals(other.right)) { - return false; - } - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("EitherOr ["); - if (isEmpty()) { - builder.append("EMPTY"); - } else if (isLeft()) { - builder.append("Left = ").append(left); - } else if (isRight()) { - builder.append("Right = ").append(right); - } - builder.append("]"); - return builder.toString(); - } - -} +/******************************************************************************* + * Copyright (c) 2017, Vernalis (R&D) Ltd + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, Version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + ******************************************************************************/ +package com.vernalis.knime.misc; + +import java.util.NoSuchElementException; +import java.util.Objects; + +/** + * A class allowing one of two different types to be provided as an argument for + * a method. Only one type is ever present. An empty instance is also possible. + * This is loosely based on the Java 1.8 'Optional' class + * + * @author s.roughley + * + * @param + * The 'left' type parameter + * @param + * The 'right' type parameter + */ +public final class EitherOr { + + private final T left; + private final U right; + + private EitherOr(T left, U right) { + this.left = left; + this.right = right; + } + + /** + * Empty Instance + */ + private static final EitherOr EMPTY = new EitherOr<>(null, null); + + /** + * Create a 'left' object + * + * @param value + * The value to hold (non-null) + * @return A 'left' container object + * @throws NullPointerException + * if a null value was supplied + */ + public static EitherOr ofLeft(T value) + throws NullPointerException { + return new EitherOr<>(Objects.requireNonNull(value), null); + } + + /** + * Create a 'right' object + * + * @param value + * The value to hold (non-null) + * @return A 'right' container object + * @throws NullPointerException + * if a null value was supplied + */ + public static EitherOr ofRight(U value) { + return new EitherOr<>(null, Objects.requireNonNull(value)); + } + + /** + * @return An empty object (containing no values) Note - use + * {@link #isEmpty()} or {@link #isPresent()} to check for + * 'emptiness' + */ + public static EitherOr empty() { + @SuppressWarnings("unchecked") + EitherOr retVal = (EitherOr) EMPTY; + return retVal; + } + + /** + * @return true if the object is a 'left' container + */ + public boolean isLeft() { + return left != null; + } + + /** + * @return true if the object is a 'right' container + */ + public boolean isRight() { + return right != null; + } + + /** + * @return true if the object contains neither left or right + * values + */ + public boolean isEmpty() { + return !isPresent(); + } + + /** + * @return true if the object contains either a left or right + * value + */ + public boolean isPresent() { + return isLeft() || isRight(); + } + + /** + * @return The non-null left value + * @throws NoSuchElementException + * if there is no stored left value + */ + public T getLeft() throws NoSuchElementException { + if (!isLeft()) { + throw new NoSuchElementException("No left value present"); + } + return left; + } + + /** + * @return The non-null right value + * @throws NoSuchElementException + * if there is no stored right value + */ + public U getRight() throws NoSuchElementException { + if (!isRight()) { + throw new NoSuchElementException("No right value present"); + } + return right; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((left == null) ? 0 : left.hashCode()); + result = prime * result + ((right == null) ? 0 : right.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof EitherOr)) { + return false; + } + EitherOr other = (EitherOr) obj; + if (left == null) { + if (other.left != null) { + return false; + } + } else if (!left.equals(other.left)) { + return false; + } + if (right == null) { + if (other.right != null) { + return false; + } + } else if (!right.equals(other.right)) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("EitherOr ["); + if (isEmpty()) { + builder.append("EMPTY"); + } else if (isLeft()) { + builder.append("Left = ").append(left); + } else if (isRight()) { + builder.append("Right = ").append(right); + } + builder.append("]"); + return builder.toString(); + } + +} diff --git a/com.vernalis.knime.database/META-INF/MANIFEST.MF b/com.vernalis.knime.database/META-INF/MANIFEST.MF index 8480c757..08f1ad0e 100644 --- a/com.vernalis.knime.database/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.database/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.database;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: library.jar Bundle-Activator: com.vernalis.knime.database.VernalisDatabaseConnectorNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.feature/feature.xml b/com.vernalis.knime.feature/feature.xml index 4f0d6958..f0c19af8 100644 --- a/com.vernalis.knime.feature/feature.xml +++ b/com.vernalis.knime.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/com.vernalis.knime.fingerprint/META-INF/MANIFEST.MF b/com.vernalis.knime.fingerprint/META-INF/MANIFEST.MF index 714447f1..801422b8 100644 --- a/com.vernalis.knime.fingerprint/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.fingerprint/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.fingerprint;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: sparsetodense.jar Bundle-Activator: com.vernalis.knime.fingerprint.SparseToDenseNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.flowcontrol/META-INF/MANIFEST.MF b/com.vernalis.knime.flowcontrol/META-INF/MANIFEST.MF index 500518dc..6dddda85 100644 --- a/com.vernalis.knime.flowcontrol/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.flowcontrol/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.flowcontrol;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: flowcontrol.jar Bundle-Activator: com.vernalis.knime.flowcontrol.FlowControlNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.io/META-INF/MANIFEST.MF b/com.vernalis.knime.io/META-INF/MANIFEST.MF index d24a1381..fd669a13 100644 --- a/com.vernalis.knime.io/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.io/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.io;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: loadtextfiles.jar Bundle-Activator: com.vernalis.knime.io.MiscIOPlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.jfcplot.core/META-INF/MANIFEST.MF b/com.vernalis.knime.jfcplot.core/META-INF/MANIFEST.MF index 960e74d6..84c7ed87 100644 --- a/com.vernalis.knime.jfcplot.core/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.jfcplot.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.jfcplot.core;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: temp.jar Bundle-Activator: com.vernalis.knime.jfcplot.core.VernalisJFreeChartCorePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.misc.gc/META-INF/MANIFEST.MF b/com.vernalis.knime.misc.gc/META-INF/MANIFEST.MF index ca7efaae..5d5edca4 100644 --- a/com.vernalis.knime.misc.gc/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.misc.gc/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.misc.gc;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: rungarbagecollector.jar Bundle-Activator: com.vernalis.knime.misc.gc.RunGarbageCollectorNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.pdbconnector/META-INF/MANIFEST.MF b/com.vernalis.knime.pdbconnector/META-INF/MANIFEST.MF index 97574d2a..d60ac8ef 100644 --- a/com.vernalis.knime.pdbconnector/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.pdbconnector/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.pdbconnector;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: pdbconnector.jar Bundle-Vendor: %Bundle-Vendor Require-Bundle: org.knime.workbench.core;bundle-version="[3.0.0,5.0.0)", diff --git a/com.vernalis.knime.perfmon/META-INF/MANIFEST.MF b/com.vernalis.knime.perfmon/META-INF/MANIFEST.MF index 8929aa8d..22d555c1 100644 --- a/com.vernalis.knime.perfmon/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.perfmon/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.perfmon;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: timingstart.jar Bundle-Activator: com.vernalis.knime.perfmon.TimingStartNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.plot.jfreechart/META-INF/MANIFEST.MF b/com.vernalis.knime.plot.jfreechart/META-INF/MANIFEST.MF index 9deb8f46..e029877d 100644 --- a/com.vernalis.knime.plot.jfreechart/META-INF/MANIFEST.MF +++ b/com.vernalis.knime.plot.jfreechart/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime.plot.jfreechart; singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: vernalisjfreechart.jar Bundle-Activator: com.vernalis.knime.plot.jfreechart.VernalisJFreeChartNodePlugin Bundle-Vendor: %Bundle-Vendor diff --git a/com.vernalis.knime.testing.feature/feature.xml b/com.vernalis.knime.testing.feature/feature.xml index 29e6a085..4bc47038 100644 --- a/com.vernalis.knime.testing.feature/feature.xml +++ b/com.vernalis.knime.testing.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/com.vernalis.knime/META-INF/MANIFEST.MF b/com.vernalis.knime/META-INF/MANIFEST.MF index ee894bf7..a733c787 100644 --- a/com.vernalis.knime/META-INF/MANIFEST.MF +++ b/com.vernalis.knime/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.vernalis.knime;singleton:=true -Bundle-Version: 1.27.3.qualifier +Bundle-Version: 1.27.4.qualifier Bundle-ClassPath: com.vernalis.knime.jar Bundle-Vendor: %Bundle-Vendor Require-Bundle: org.knime.workbench.core;bundle-version="[3.0.0,5.0.0)", diff --git a/com.vernalis.knime/dir_conflicts.prej b/com.vernalis.knime/dir_conflicts.prej deleted file mode 100644 index b5ed380c..00000000 --- a/com.vernalis.knime/dir_conflicts.prej +++ /dev/null @@ -1,6 +0,0 @@ -Trying to delete property 'svn:mergeinfo' -but the property has been locally modified. -<<<<<<< (local property value) -/branches/RDKit_Refactored_And_Wizard_30July2012/com.vernalis/com.vernalis.knime:3758-4163 -/branches/v_2_7/com.vernalis/com.vernalis.knime:6364-6408======= ->>>>>>> (incoming property value)