WICKET-6025 Read resource files with Java's NIO API
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/e0c2f1bb Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/e0c2f1bb Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/e0c2f1bb Branch: refs/heads/lambdas Commit: e0c2f1bbae576d26f2dc54996905e9acb63ccca0 Parents: 6355d71 Author: Tobias Soloschenko <[email protected]> Authored: Sun Nov 1 09:22:57 2015 +0100 Committer: Tobias Soloschenko <[email protected]> Committed: Fri Nov 6 22:41:38 2015 +0100 ---------------------------------------------------------------------- .../FileSystemResourceStreamReference.java | 29 +++ .../wicket/resource/FileSystemResource.java | 130 +++++++++++ .../resource/FileSystemResourceReference.java | 170 +++++++++++++++ .../services/java.nio.file.spi.FileTypeDetector | 1 + .../wicket/filetype/TestFileTypeDetector.java | 42 ++++ .../resource/FileSystemResourceReference.txt | 1 + .../resource/FileSystemResourceReference.uke | 1 + .../FileSystemResourceReferenceTest.java | 218 +++++++++++++++++++ .../FileSystemResourceReferenceTest.zip | Bin 0 -> 986 bytes .../util/resource/FileSystemResourceStream.java | 169 ++++++++++++++ 10 files changed, 761 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/caching/FileSystemResourceStreamReference.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/caching/FileSystemResourceStreamReference.java b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/caching/FileSystemResourceStreamReference.java new file mode 100644 index 0000000..1feae37 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/caching/FileSystemResourceStreamReference.java @@ -0,0 +1,29 @@ +package org.apache.wicket.core.util.resource.locator.caching; + +import java.nio.file.Paths; + +import org.apache.wicket.util.resource.FileSystemResourceStream; + +/** + * A reference which can be used to recreate {@link FileSystemResourceStream} + * + * @author Tobias Soloschenko + */ +public class FileSystemResourceStreamReference extends AbstractResourceStreamReference +{ + private final String absolutePath; + + FileSystemResourceStreamReference(final FileSystemResourceStream fileSystemResourceStream) + { + absolutePath = fileSystemResourceStream.getPath().toAbsolutePath().toString(); + saveResourceStream(fileSystemResourceStream); + } + + @Override + public FileSystemResourceStream getReference() + { + FileSystemResourceStream fileSystemResourceStream = new FileSystemResourceStream(Paths.get(absolutePath)); + restoreResourceStream(fileSystemResourceStream); + return fileSystemResourceStream; + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResource.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResource.java b/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResource.java new file mode 100644 index 0000000..56e1b95 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResource.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; + +import org.apache.wicket.Application; +import org.apache.wicket.WicketRuntimeException; +import org.apache.wicket.request.cycle.RequestCycle; +import org.apache.wicket.request.resource.AbstractResource; +import org.apache.wicket.request.resource.PartWriterCallback; +import org.apache.wicket.util.lang.Args; + +/** + * Used to provide resources based on the on Java NIO FileSystem API.<br> + * <br> + * For more information see {@link org.apache.wicket.markup.html.media.FileSystemResourceReference} + * + * @author Tobias Soloschenko + * + */ +public class FileSystemResource extends AbstractResource +{ + private static final long serialVersionUID = 1L; + + private final Path path; + + /** + * Creates a new file system resource based on the given path + * + * @param path + * the path to be read for the resource + */ + public FileSystemResource(Path path) + { + Args.notNull(path, "path"); + this.path = path; + } + + /** + * Creates a new resource response and reads the given path + */ + @Override + protected ResourceResponse newResourceResponse(Attributes attributes) + { + try + { + long size = getSize(); + ResourceResponse resourceResponse = new ResourceResponse(); + resourceResponse.setContentType(getMimeType()); + resourceResponse.setAcceptRange(ContentRangeType.BYTES); + resourceResponse.setContentLength(size); + RequestCycle cycle = RequestCycle.get(); + Long startbyte = cycle.getMetaData(CONTENT_RANGE_STARTBYTE); + Long endbyte = cycle.getMetaData(CONTENT_RANGE_ENDBYTE); + resourceResponse.setWriteCallback(new PartWriterCallback(getInputStream(), size, + startbyte, endbyte)); + return resourceResponse; + } + catch (IOException e) + { + throw new WicketRuntimeException( + "An error occured while processing the media resource response", e); + } + } + + /** + * Gets the size of the resource + * + * @return the size of the resource + * @throws IOException + * if the size attribute can't be read + */ + protected long getSize() throws IOException + { + return Files.readAttributes(path, BasicFileAttributes.class).size(); + } + + /** + * Gets the mime type to be used for the response it first uses the URL connection to get the + * mime type and after this the FileTypeDetector SPI is used. + * + * @return the mime type to be used for the response + * @throws IOException + * if the mime type could'nt be resoulved + */ + protected String getMimeType() throws IOException + { + String mimeType = null; + if (Application.exists()) + { + mimeType = Application.get().getMimeType(path.getFileName().toString()); + } + if (mimeType == null) + { + mimeType = Files.probeContentType(path); + } + return mimeType; + } + + /** + * Gets the input stream of the given path + * + * @return the input stream of the given path + * @throws IOException + * if there is an exception while receiving the input stream + */ + protected InputStream getInputStream() throws IOException + { + return Files.newInputStream(path); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResourceReference.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResourceReference.java b/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResourceReference.java new file mode 100644 index 0000000..e10fe54 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/resource/FileSystemResourceReference.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.resource; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +import org.apache.wicket.Application; +import org.apache.wicket.MetaDataKey; +import org.apache.wicket.request.resource.IResource; +import org.apache.wicket.request.resource.ResourceReference; +import org.apache.wicket.util.lang.Args; + +/** + * This resource reference is used to provide a reference to a resource based on Java NIO FileSystem + * API.<br> + * <br> + * To implement a mime type detection refer to the documentation of + * {@link java.nio.file.Files#probeContentType(Path)} and provide an implementation for + * java.nio.file.spi.FileTypeDetector in the META-INF/services folder for jars or in the + * /WEB-INF/classes/META-INF/services folder for webapps<br> + * <br> + * You can optionally override {@link #getFileSystemResource()} to provide an inline mime type detection, + * which is preferred to the default detection.<br> + * <br> + * Example: + * + * <pre> + * <code> + * Path path = FileSystemResourceReference.getPath(URI.create("jar:file:///folder/file.zip!/folderInZip/video.mp4")); + * add(new Video("video", new FileSystemResourceReference(path))); + * </code> + * </pre> + * + * @author Tobias Soloschenko + */ +public class FileSystemResourceReference extends ResourceReference +{ + private static final long serialVersionUID = 1L; + + private final Path path; + + /** The key for the file system meta data **/ + public static final MetaDataKey<Map<URI, FileSystem>> FILE_SYSTEM_META_DATA_KEY = new MetaDataKey<Map<URI, FileSystem>>() + { + private static final long serialVersionUID = 1L; + }; + + /** + * Creates a file system resource reference based on the given path + * + * @param name + * the name of the resource reference to expose data + * @param path + * the path to create the resource reference + */ + public FileSystemResourceReference(String name, Path path) + { + super(name); + Args.notNull(path, "path"); + this.path = path; + } + + /** + * Creates a new {@link org.apache.wicket.markup.html.media.FileSystemResource} and applies the + * path to it. + */ + @Override + public IResource getResource() + { + return getFileSystemResource(); + } + + /** + * Gets the file system resource to be used for the resource reference + * + * @return the file system resource to be used for the resource reference + */ + protected FileSystemResource getFileSystemResource() + { + return new FileSystemResource(path); + } + + /** + * Creates a path and a file system (if required) based on the given URI + * + * @param uri + * the URI to create the file system and the path of + * @param env + * the environment parameter to create the file system with + * @return the path of the file in the file system + * @throws IOException + * if the file system could'nt be created + * @throws URISyntaxException + * if the URI has no valid syntax + */ + public static Path getPath(URI uri, Map<String, String> env) throws IOException, + URISyntaxException + { + String uriString = uri.toString(); + int indexOfExclamationMark = uriString.indexOf('!'); + if (indexOfExclamationMark == -1) + { + return Paths.get(uri); + } + String zipFile = uriString.substring(0, indexOfExclamationMark); + FileSystem fileSystem = null; + + synchronized (FILE_SYSTEM_META_DATA_KEY) + { + Map<URI, FileSystem> metaData = Application.get() + .getMetaData(FILE_SYSTEM_META_DATA_KEY); + if (metaData == null) + { + metaData = new HashMap<URI, FileSystem>(); + Application.get().setMetaData(FILE_SYSTEM_META_DATA_KEY, metaData); + } + if (fileSystem == null) + { + if (env == null) + { + env = new HashMap<>(); + env.put("create", "true"); + env.put("encoding", "UTF-8"); + } + fileSystem = FileSystems.newFileSystem(new URI(zipFile), env); + metaData.put(uri, fileSystem); + } + } + String fileName = uriString.substring(uriString.indexOf('!') + 1); + return fileSystem.getPath(fileName); + } + + /** + * Creates a path and a file system (if required) based on the given URI + * + * @param uri + * the URI to create the file system and the path of + * @return the path of the file in the file system + * @throws IOException + * if the file system could'nt be created + * @throws URISyntaxException + * if the URI has no valid syntax + */ + public static Path getPath(URI uri) throws IOException, URISyntaxException + { + return getPath(uri, null); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/test/java/META-INF/services/java.nio.file.spi.FileTypeDetector ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/META-INF/services/java.nio.file.spi.FileTypeDetector b/wicket-core/src/test/java/META-INF/services/java.nio.file.spi.FileTypeDetector new file mode 100644 index 0000000..475e050 --- /dev/null +++ b/wicket-core/src/test/java/META-INF/services/java.nio.file.spi.FileTypeDetector @@ -0,0 +1 @@ +org.apache.wicket.filetype.TestFileTypeDetector \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/test/java/org/apache/wicket/filetype/TestFileTypeDetector.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/filetype/TestFileTypeDetector.java b/wicket-core/src/test/java/org/apache/wicket/filetype/TestFileTypeDetector.java new file mode 100644 index 0000000..115bebe --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/filetype/TestFileTypeDetector.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.filetype; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.spi.FileTypeDetector; + +/** + * File type detector for unit tests of file system resource reference + * + * @author Tobias Soloschenko + * + */ +public class TestFileTypeDetector extends FileTypeDetector +{ + + @Override + public String probeContentType(Path path) throws IOException + { + if(path.getFileName().toString().contains("FileSystemResourceReference")){ + return "text/plain_provided_by_detector"; + }else{ + return null; + } + } + +} http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.txt ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.txt b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.txt new file mode 100644 index 0000000..3fa4830 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.txt @@ -0,0 +1 @@ +FileSystemResourceReference.zip content in normal file \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.uke ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.uke b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.uke new file mode 100644 index 0000000..3fa4830 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReference.uke @@ -0,0 +1 @@ +FileSystemResourceReference.zip content in normal file \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.java b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.java new file mode 100644 index 0000000..acbb986 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.java @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; + +import org.apache.wicket.util.io.ByteArrayOutputStream; +import org.apache.wicket.util.io.IOUtils; +import org.apache.wicket.util.tester.WicketTestCase; +import org.junit.Assert; +import org.junit.Test; + +/** + * Test for FileSystemResourceReference + * + * @author Tobias Soloschenko + * + */ +public class FileSystemResourceReferenceTest extends WicketTestCase +{ + + /** + * Test ZIP files + * + * @throws IOException + * if the ZIP file or the file content can't be read + * @throws URISyntaxException + * if the URI is not readable + */ + @Test + public void testFileSystemResourceReferenceWithZip() throws IOException, URISyntaxException + { + InputStream inputStream = null; + try + { + URL resource = FileSystemResourceReferenceTest.class.getResource("FileSystemResourceReferenceTest.zip"); + Path path = FileSystemResourceReference.getPath(URI.create("jar:" + resource.toURI() + + "!/folderInZip/FileSystemResourceReference.txt")); + final FileSystemResource fileSystemResource = new FileSystemResource(path); + FileSystemResourceReference fileSystemResourceReference = new FileSystemResourceReference( + "test", path) + { + private static final long serialVersionUID = 1L; + + @Override + protected FileSystemResource getFileSystemResource() + { + return fileSystemResource; + } + }; + // Size + Assert.assertEquals(fileSystemResource.getSize(), 39); + + // Content + inputStream = fileSystemResource.getInputStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + IOUtils.copy(inputStream, outputStream); + Assert.assertEquals("FileSystemResourceReference.zip content", outputStream.toString()); + } + finally + { + IOUtils.closeQuietly(inputStream); + } + } + + /** + * Test normal files + * + * @throws IOException + * if the file can't be read + * @throws URISyntaxException + * if the URI is not readable + */ + @Test + public void testFileSystemResourceReferenceWithNormalFile() throws IOException, + URISyntaxException + { + InputStream inputStream = null; + try + { + URL resource = FileSystemResourceReferenceTest.class.getResource("FileSystemResourceReference.txt"); + Path path = FileSystemResourceReference.getPath(resource.toURI()); + final FileSystemResource fileSystemResource = new FileSystemResource(path); + FileSystemResourceReference fileSystemResourceReference = new FileSystemResourceReference( + "test", path) + { + private static final long serialVersionUID = 1L; + + @Override + protected FileSystemResource getFileSystemResource() + { + return fileSystemResource; + } + }; + // Size + Assert.assertEquals(fileSystemResource.getSize(), 54); + + // Content + inputStream = fileSystemResource.getInputStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + IOUtils.copy(inputStream, outputStream); + Assert.assertEquals("FileSystemResourceReference.zip content in normal file", + outputStream.toString()); + } + finally + { + IOUtils.closeQuietly(inputStream); + } + } + + /** + * Test mime types + * + * @throws IOException + * if the file or the mime type can't be read + * @throws URISyntaxException + * if the URI is not readable + */ + @Test + public void testMimeTypeEqual() throws IOException, URISyntaxException + { + URL resource = FileSystemResourceReferenceTest.class.getResource("FileSystemResourceReference.txt"); + Path path = FileSystemResourceReference.getPath(resource.toURI()); + final FileSystemResource fileSystemResource = new FileSystemResource(path) + { + + private static final long serialVersionUID = 1L; + + protected String getMimeType() throws IOException + { + return "test/mime1"; + } + }; + FileSystemResourceReference fileSystemResourceReference = new FileSystemResourceReference( + "test", path) + { + private static final long serialVersionUID = 1L; + + @Override + protected FileSystemResource getFileSystemResource() + { + return fileSystemResource; + } + }; + Assert.assertEquals("test/mime1", fileSystemResource.getMimeType()); + } + + /** + * Test mime type detection with java.nio.file.spi.FileTypeDetector + * + * @throws IOException + * if the file can't be read + * @throws URISyntaxException + * if the + */ + @Test + public void testMimeTypeDetection() throws IOException, URISyntaxException + { + // uke > unknown extension :-) + URL resource = FileSystemResourceReferenceTest.class.getResource("FileSystemResourceReference.uke"); + Path path = FileSystemResourceReference.getPath(resource.toURI()); + + final FileSystemResource fileSystemResource = new FileSystemResource(path); + FileSystemResourceReference fileSystemResourceReference = new FileSystemResourceReference( + "test", path) + { + private static final long serialVersionUID = 1L; + + protected FileSystemResource getFileSystemResource() + { + return fileSystemResource; + + } + }; + Assert.assertEquals("text/plain_provided_by_detector", fileSystemResource.getMimeType()); + + final FileSystemResource fileSystemResourceMime = new FileSystemResource(path) + { + private static final long serialVersionUID = 1L; + + protected String getMimeType() throws IOException + { + return "text/plain"; + } + }; + FileSystemResourceReference fileSystemResourceReferenceOverriddenMime = new FileSystemResourceReference( + "test", path) + { + private static final long serialVersionUID = 1L; + + @Override + protected FileSystemResource getFileSystemResource() + { + return fileSystemResourceMime; + } + }; + Assert.assertEquals("text/plain", fileSystemResourceMime.getMimeType()); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.zip ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.zip b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.zip new file mode 100644 index 0000000..7b77d43 Binary files /dev/null and b/wicket-core/src/test/java/org/apache/wicket/resource/FileSystemResourceReferenceTest.zip differ http://git-wip-us.apache.org/repos/asf/wicket/blob/e0c2f1bb/wicket-util/src/main/java/org/apache/wicket/util/resource/FileSystemResourceStream.java ---------------------------------------------------------------------- diff --git a/wicket-util/src/main/java/org/apache/wicket/util/resource/FileSystemResourceStream.java b/wicket-util/src/main/java/org/apache/wicket/util/resource/FileSystemResourceStream.java new file mode 100644 index 0000000..61bd226 --- /dev/null +++ b/wicket-util/src/main/java/org/apache/wicket/util/resource/FileSystemResourceStream.java @@ -0,0 +1,169 @@ +package org.apache.wicket.util.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; + +import org.apache.wicket.util.file.File; +import org.apache.wicket.util.lang.Args; +import org.apache.wicket.util.lang.Bytes; +import org.apache.wicket.util.time.Time; + +/** + * A FileSystemResourceStream is an IResourceStream implementation for Java NIO paths. + * + * @see org.apache.wicket.util.resource.IResourceStream + * @see org.apache.wicket.util.watch.IModifiable + * @author Tobias Soloschenko + */ +public class FileSystemResourceStream extends AbstractResourceStream + implements + IFixedLocationResourceStream +{ + private static final long serialVersionUID = 1L; + + /** Any associated path */ + private final Path path; + + /** Resource stream */ + private transient InputStream inputStream; + + /** + * Constructor. + * + * @param path + * {@link Path} containing resource + */ + public FileSystemResourceStream(final Path path) + { + Args.notNull(path, "path"); + this.path = path; + } + + /** + * Constructor. + * + * @param file + * {@link java.io.File} containing resource + */ + public FileSystemResourceStream(final java.io.File file) + { + Args.notNull(file, "file"); + this.path = file.toPath(); + } + + /** + * Constructor. + * + * @param file + * {@link File} containing resource + */ + public FileSystemResourceStream(final File file) + { + Args.notNull(file, "file"); + this.path = file.toPath(); + } + + @Override + public InputStream getInputStream() throws ResourceStreamNotFoundException + { + if (inputStream == null) + { + try + { + inputStream = Files.newInputStream(path); + } + catch (IOException e) + { + throw new ResourceStreamNotFoundException("Input stream of path " + path + + " could not be acquired", e); + } + } + return inputStream; + } + + @Override + public void close() throws IOException + { + if (inputStream != null) + { + inputStream.close(); + inputStream = null; + } + } + + @Override + public String getContentType() + { + try + { + String contentType = Files.probeContentType(path); + if (contentType == null) + { + contentType = URLConnection.getFileNameMap().getContentTypeFor( + path.getFileName().toString()); + } + return contentType; + } + catch (IOException e) + { + throw new RuntimeException("Content type of path " + path + " could not be acquired", e); + } + } + + /** + * @return The path this resource resides in, if any. + */ + public final Path getPath() + { + return path; + } + + @Override + public Time lastModifiedTime() + { + try + { + BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class); + FileTime lastModifiedTime = attributes.lastModifiedTime(); + long millis = lastModifiedTime.toMillis(); + return Time.millis(millis); + } + catch (IOException e) + { + throw new RuntimeException("Modification time of path " + path + + " could not be acquired", e); + } + } + + @Override + public Bytes length() + { + try + { + BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class); + long size = attributes.size(); + return Bytes.bytes(size); + } + catch (IOException e) + { + throw new RuntimeException("Length of path " + path + " could not be acquired", e); + } + } + + @Override + public String locationAsString() + { + return path.toString(); + } + + @Override + public String toString() + { + return locationAsString(); + } +}
