Merge pull request #115 from apache/Resources

Fix getResources in the case of file paths with spaces.
diff --git a/src/main/java/org/apache/datasketches/memory/Util.java b/src/main/java/org/apache/datasketches/memory/Util.java
index 7599321..10b3eb5 100644
--- a/src/main/java/org/apache/datasketches/memory/Util.java
+++ b/src/main/java/org/apache/datasketches/memory/Util.java
@@ -21,12 +21,21 @@
 
 import static org.apache.datasketches.memory.UnsafeUtil.checkBounds;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.Random;
 
 /**
  * @author Lee Rhodes
  */
 public final class Util {
+  private static final String LS = System.getProperty("line.separator");
+
   private Util() { }
 
   /**
@@ -255,4 +264,53 @@
     }
   }
 
+  //Resources
+
+  /**
+   * Gets the absolute path of the given resource file's shortName.
+   *
+   * <p>Note that the ClassLoader.getResource(shortName) returns a URL,
+   * which can have special characters, e.g., "%20" for spaces. This method
+   * obtains the URL, converts it to a URI, then does a uri.getPath(), which
+   * decodes any special characters in the URI path. This is required to make
+   * obtaining resources operating-system independent.</p>
+   *
+   * @param shortFileName the last name in the pathname's name sequence.
+   * @return the absolute path of the given resource file's shortName.
+   */
+  public static String getResourcePath(final String shortFileName) {
+    try {
+      final URL url = Util.class.getClassLoader().getResource(shortFileName);
+      final URI uri = url.toURI();
+      final String path = uri.getPath(); //decodes any special characters
+      return path;
+    } catch (final NullPointerException | URISyntaxException e) {
+      throw new IllegalArgumentException("Cannot find resource: " + shortFileName + LS + e);
+    }
+  }
+
+  /**
+   * Gets the file defined by the given resource file's shortFileName.
+   * @param shortFileName the last name in the pathname's name sequence.
+   * @return the file defined by the given resource file's shortFileName.
+   */
+  public static File getResourceFile(final String shortFileName) {
+    return new File(getResourcePath(shortFileName));
+  }
+
+  /**
+   * Returns a byte array of the contents of the file defined by the given resource file's
+   * shortFileName.
+   * @param shortFileName the last name in the pathname's name sequence.
+   * @return a byte array of the contents of the file defined by the given resource file's
+   * shortFileName.
+   */
+  public static byte[] getResourceBytes(final String shortFileName) {
+    try {
+      return Files.readAllBytes(Paths.get(getResourcePath(shortFileName)));
+    } catch (final IOException e) {
+      throw new IllegalArgumentException("Cannot read resource: " + shortFileName + LS + e);
+    }
+  }
+
 }
diff --git a/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java b/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java
index 8611b41..c3e2bb6 100644
--- a/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java
+++ b/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java
@@ -23,6 +23,7 @@
 
 package org.apache.datasketches.memory;
 
+import static org.apache.datasketches.memory.Util.*;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
@@ -37,16 +38,17 @@
 
 @SuppressWarnings("javadoc")
 public class AllocateDirectMapMemoryTest {
+  private static final String LS = System.getProperty("line.separator");
   MapHandle hand = null;
 
   @BeforeClass
   public void setReadOnly() {
-    UtilTest.setGettysburgAddressFileToReadOnly(this);
+    UtilTest.setGettysburgAddressFileToReadOnly();
   }
 
   @Test
   public void simpleMap() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     try (MapHandle rh = Memory.map(file)) {
       rh.close();
     }
@@ -54,7 +56,7 @@
 
   @Test
   public void testIllegalArguments() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     try (MapHandle rh = Memory.map(file, -1, Integer.MAX_VALUE, ByteOrder.nativeOrder())) {
       fail("Failed: testIllegalArgumentException: Position was negative.");
     } catch (IllegalArgumentException e) {
@@ -70,7 +72,7 @@
 
   @Test
   public void testMapAndMultipleClose() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
     try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
       Memory map = rh.get();
@@ -85,7 +87,7 @@
 
   @Test
   public void testReadFailAfterClose() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
     try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
       Memory mmf = rh.get();
@@ -98,7 +100,7 @@
 
   @Test
   public void testLoad() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
     try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
       rh.load();
@@ -109,7 +111,7 @@
 
   @Test
   public void testHandlerHandoffWithTWR() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
     Memory mem;
     try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
@@ -124,7 +126,7 @@
 
   @Test
   public void testHandoffWithoutClose() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
     MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder());
     rh.load();
@@ -149,10 +151,18 @@
     println("PRINTING: "+this.getClass().getName());
   }
 
-  /**
-   * @param s value to print
-   */
-  static void println(String s) {
-    //System.out.println(s); //disable here
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
   }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
 }
diff --git a/src/test/java/org/apache/datasketches/memory/AllocateDirectWritableMapMemoryTest.java b/src/test/java/org/apache/datasketches/memory/AllocateDirectWritableMapMemoryTest.java
index aa2bda1..f1eadc1 100644
--- a/src/test/java/org/apache/datasketches/memory/AllocateDirectWritableMapMemoryTest.java
+++ b/src/test/java/org/apache/datasketches/memory/AllocateDirectWritableMapMemoryTest.java
@@ -23,6 +23,7 @@
 
 package org.apache.datasketches.memory;
 
+import static org.apache.datasketches.memory.Util.*;
 import static org.apache.datasketches.memory.AllocateDirectMap.isFileReadOnly;
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.testng.Assert.assertEquals;
@@ -42,16 +43,16 @@
 
 @SuppressWarnings("javadoc")
 public class AllocateDirectWritableMapMemoryTest {
+  private static final String LS = System.getProperty("line.separator");
 
   @BeforeClass
   public void setReadOnly() {
-    UtilTest.setGettysburgAddressFileToReadOnly(this);
+    UtilTest.setGettysburgAddressFileToReadOnly();
   }
 
   @Test
   public void simpleMap() throws Exception {
-    File file =
-        new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     try (MapHandle h = Memory.map(file); WritableMapHandle wh = (WritableMapHandle) h) {
       Memory mem = h.get();
       byte[] bytes = new byte[(int)mem.getCapacity()];
@@ -138,8 +139,7 @@
 
   @Test(expectedExceptions = ReadOnlyException.class)
   public void simpleMap2() throws IOException {
-    File file =
-        new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     assertTrue(isFileReadOnly(file));
     try (WritableMapHandle rh = WritableMemory.map(file)) {
       //
@@ -148,8 +148,7 @@
 
   @Test(expectedExceptions = IllegalArgumentException.class)
   public void checkOverLength()  {
-    File file =
-        new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     try (WritableMapHandle rh = WritableMemory.map(file, 0, 1 << 20, ByteOrder.nativeOrder())) {
       //
     } catch (IOException e) {
@@ -210,8 +209,7 @@
 
   @Test
   public void checkExplicitClose() throws Exception {
-    File file =
-        new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     try (MapHandle wmh = Memory.map(file)) {
       wmh.close(); //explicit close. Does the work of closing
       wmh.dirMap.close(); //redundant
@@ -232,10 +230,18 @@
     println("PRINTING: "+this.getClass().getName());
   }
 
-  /**
-   * @param s String to print
-   */
-  static void println(final String s) {
-    //System.out.println(s);
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
   }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
 }
diff --git a/src/test/java/org/apache/datasketches/memory/MemoryTest.java b/src/test/java/org/apache/datasketches/memory/MemoryTest.java
index 996e511..d70e6fd 100644
--- a/src/test/java/org/apache/datasketches/memory/MemoryTest.java
+++ b/src/test/java/org/apache/datasketches/memory/MemoryTest.java
@@ -23,6 +23,7 @@
 
 package org.apache.datasketches.memory;
 
+import static org.apache.datasketches.memory.Util.*;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
@@ -41,10 +42,11 @@
 
 @SuppressWarnings("javadoc")
 public class MemoryTest {
+  private static final String LS = System.getProperty("line.separator");
 
   @BeforeClass
   public void setReadOnly() {
-    UtilTest.setGettysburgAddressFileToReadOnly(this);
+    UtilTest.setGettysburgAddressFileToReadOnly();
   }
 
   @Test
@@ -397,7 +399,7 @@
   @SuppressWarnings("resource")
   @Test
   public void checkMonitorDirectMapStats() throws Exception {
-    File file = new File(getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+    File file = getResourceFile("GettysburgAddress.txt");
     long bytes = file.length();
 
     MapHandle mmh1 = Memory.map(file);
@@ -458,11 +460,18 @@
     println("PRINTING: "+this.getClass().getName());
   }
 
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
   /**
-   * @param s value to print
+   * @param o value to print
    */
-  static void println(final String s) {
-    //System.out.println(s);
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
   }
 
 }
diff --git a/src/test/java/org/apache/datasketches/memory/UtilTest.java b/src/test/java/org/apache/datasketches/memory/UtilTest.java
index 63fad1b..d174ffa 100644
--- a/src/test/java/org/apache/datasketches/memory/UtilTest.java
+++ b/src/test/java/org/apache/datasketches/memory/UtilTest.java
@@ -24,6 +24,8 @@
 package org.apache.datasketches.memory;
 
 import static org.apache.datasketches.memory.Util.characterPad;
+import static org.apache.datasketches.memory.Util.getResourceFile;
+import static org.apache.datasketches.memory.Util.getResourceBytes;
 import static org.apache.datasketches.memory.Util.negativeCheck;
 import static org.apache.datasketches.memory.Util.nullCheck;
 import static org.apache.datasketches.memory.Util.zeroCheck;
@@ -44,6 +46,7 @@
 
 @SuppressWarnings("javadoc")
 public class UtilTest {
+  private static final String LS = System.getProperty("line.separator");
 
   //Binary Search
   @Test
@@ -142,9 +145,8 @@
     }
   }
 
-  static final void setGettysburgAddressFileToReadOnly(Object obj) {
-    File file =
-        new File(obj.getClass().getClassLoader().getResource("GettysburgAddress.txt").getFile());
+  static final void setGettysburgAddressFileToReadOnly() {
+    File file = getResourceFile("GettysburgAddress.txt");
     try {
     Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("r--r--r--"));
     } catch (IOException e) {
@@ -152,16 +154,51 @@
     }
   }
 
+  //Resources
+
+  @Test
+  public void resourceFileExits() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final File file = getResourceFile(shortFileName);
+    assertTrue(file.exists());
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void resourceFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceFile(shortFileName + "123");
+  }
+
+  @Test
+  public void resourceBytesCorrect() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final byte[] bytes = getResourceBytes(shortFileName);
+    assertTrue(bytes.length == 1541);
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void resourceBytesFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceBytes(shortFileName + "123");
+  }
+
   @Test
   public void printlnTest() {
     println("PRINTING: "+this.getClass().getName());
   }
 
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
   /**
-   * @param s value to print
+   * @param o value to print
    */
-  static void println(String s) {
-    //System.out.println(s); //disable here
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
   }
 
 }