View Javadoc
1   package org.djutils.io;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertNotNull;
5   import static org.junit.jupiter.api.Assertions.assertNull;
6   
7   import java.io.File;
8   import java.io.FileInputStream;
9   import java.io.FileNotFoundException;
10  import java.io.FileOutputStream;
11  import java.io.IOException;
12  import java.io.InputStream;
13  import java.net.URISyntaxException;
14  import java.net.URL;
15  import java.nio.file.Files;
16  import java.nio.file.Paths;
17  import java.util.ArrayList;
18  import java.util.Arrays;
19  import java.util.List;
20  import java.util.jar.JarEntry;
21  import java.util.jar.JarOutputStream;
22  
23  import org.junit.jupiter.api.Test;
24  
25  /**
26   * URLResourceTest.java.
27   * <p>
28   * Copyright (c) 2002-2025 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
29   * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
30   * distributed under a three-clause BSD-style license, which can be found at
31   * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
32   * </p>
33   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
34   */
35  public class URLResourceTest
36  {
37      /**
38       * Test whether URLResource retrieves files.
39       * @throws IOException on I/O error
40       * @throws URISyntaxException on URL error
41       */
42      @SuppressWarnings("deprecation")
43      @Test
44      public final void resourceTest() throws IOException, URISyntaxException
45      {
46          URL url = URLResource.getResource("/org/djutils-test-resources/test.txt");
47          String absolutePath = url.toURI().getPath();
48          List<String> lines = Files.readAllLines(Paths.get(url.toURI()));
49          assertEquals(3, lines.size());
50          assertEquals("abc", lines.get(0));
51  
52          url = null;
53          lines = null;
54  
55          url = URLResource.getResource("test.txt", "/org/djutils-test-resources/");
56          lines = Files.readAllLines(Paths.get(url.toURI()));
57          assertEquals(3, lines.size());
58          assertEquals("def", lines.get(1));
59  
60          url = null;
61          lines = null;
62  
63          url = URLResource.getResource("/org/djutils-test-resources/test.txt", "/");
64          lines = Files.readAllLines(Paths.get(url.toURI()));
65          assertEquals(3, lines.size());
66          assertEquals("ghi", lines.get(2));
67  
68          url = null;
69          lines = null;
70  
71          url = URLResource.getResource("file://" + absolutePath);
72          lines = Files.readAllLines(Paths.get(url.toURI()));
73          assertEquals(3, lines.size());
74          assertEquals("abc", lines.get(0));
75      }
76  
77      /**
78       * Test whether URLResource retrieves files.
79       * @throws IOException on I/O error
80       * @throws URISyntaxException on URL error
81       */
82      @SuppressWarnings("deprecation")
83      @Test
84      public final void resourceAsStreamTest() throws IOException, URISyntaxException
85      {
86          InputStream stream = URLResource.getResourceAsStream("/org/djutils-test-resources/test.txt");
87          byte[] barr = readAllBytes(stream);
88          stream.close();
89          assertEquals('a', barr[0]);
90  
91          assertNull(URLResource.getResourceAsStream("xxx:///org::djutils-test-resources<>test.txt"));
92  
93          stream = URLResource.getResourceAsStream("/org/djutils-test-resources/test123.txt");
94          assertNull(stream);
95      }
96  
97      /**
98       * Test whether URLResource retrieves files.
99       * @throws IOException on I/O error
100      * @throws URISyntaxException on error
101      */
102     @SuppressWarnings("deprecation")
103     @Test
104     public final void jarTest() throws IOException, URISyntaxException
105     {
106         // create a temporary jar file.
107         File jarFile = File.createTempFile("filetest-", ".jar");
108         File file1 = File.createTempFile("filetest-", ".f1");
109         File file2 = File.createTempFile("filetest-", ".f2");
110         File file3 = File.createTempFile("filetest-", ".f3");
111 
112         FileOutputStream fos = new FileOutputStream(jarFile.getAbsolutePath());
113         JarOutputStream jos = new JarOutputStream(fos);
114         addToJarFile(file1.getAbsolutePath(), jos);
115         addToJarFile(file2.getAbsolutePath(), jos);
116         addToJarFile(file3.getAbsolutePath(), jos);
117         jos.close();
118         fos.close();
119 
120         String jarFilePath = jarFile.getAbsolutePath();
121         URL jarURL = URLResource.getResource(jarFilePath);
122         assertNotNull(jarURL);
123         // System.out.println(jarFile.getAbsolutePath() + "!" + file1.getName());
124         // URL jar1 = URLResource.getResource(jarFile.getAbsolutePath() + "!" + file1.getName());
125         // System.out.println(jar1.toURI());
126         // assertNotNull(jar1);
127     }
128 
129     /**
130      * Copy a plain file into a jar file.
131      * @param fileName name of the file to copy
132      * @param jos stream for writing into the jar file
133      * @throws FileNotFoundException when the input file could not be found
134      * @throws IOException when the input file could not be read, or writing to the jar stream fails
135      */
136     public void addToJarFile(final String fileName, final JarOutputStream jos) throws FileNotFoundException, IOException
137     {
138         File file = new File(fileName);
139         FileInputStream fis = new FileInputStream(file);
140         JarEntry zipEntry = new JarEntry(file.getName());
141         jos.putNextEntry(zipEntry);
142         byte[] bytes = new byte[1024];
143         int length;
144         while ((length = fis.read(bytes)) >= 0)
145         {
146             jos.write(bytes, 0, length);
147         }
148         jos.closeEntry();
149         fis.close();
150     }
151 
152     /**
153      * Copied from Java 13 to handle readAllBytes in Java 8.
154      * @param stream the input stream to read the bytes from
155      * @return the byte array
156      * @throws IOException on I/O error
157      */
158     private byte[] readAllBytes(final InputStream stream) throws IOException
159     {
160         List<byte[]> bufs = null;
161         byte[] result = null;
162         int total = 0;
163         int remaining = Integer.MAX_VALUE;
164         int n;
165         do
166         {
167             byte[] buf = new byte[Math.min(remaining, 8192)];
168             int nread = 0;
169 
170             // read to EOF which may read more or less than buffer size
171             while ((n = stream.read(buf, nread, Math.min(buf.length - nread, remaining))) > 0)
172             {
173                 nread += n;
174                 remaining -= n;
175             }
176 
177             if (nread > 0)
178             {
179                 if (Integer.MAX_VALUE - 8 - total < nread)
180                 {
181                     throw new OutOfMemoryError("Required array size too large");
182                 }
183                 total += nread;
184                 if (result == null)
185                 {
186                     result = buf;
187                 }
188                 else
189                 {
190                     if (bufs == null)
191                     {
192                         bufs = new ArrayList<>();
193                         bufs.add(result);
194                     }
195                     bufs.add(buf);
196                 }
197             }
198             // if the last call to read returned -1 or the number of bytes
199             // requested have been read then break
200         }
201         while (n >= 0 && remaining > 0);
202 
203         if (bufs == null)
204         {
205             if (result == null)
206             {
207                 return new byte[0];
208             }
209             return result.length == total ? result : Arrays.copyOf(result, total);
210         }
211 
212         result = new byte[total];
213         int offset = 0;
214         remaining = total;
215         for (byte[] b : bufs)
216         {
217             int count = Math.min(b.length, remaining);
218             System.arraycopy(b, 0, result, offset, count);
219             offset += count;
220             remaining -= count;
221         }
222 
223         return result;
224 
225     }
226 }