001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.resource;
018
019import java.io.IOException;
020import java.net.URI;
021import java.net.URISyntaxException;
022import java.nio.file.Path;
023import java.nio.file.Paths;
024import java.util.Iterator;
025import java.util.Map;
026import java.util.ServiceLoader;
027
028import org.apache.wicket.WicketRuntimeException;
029import org.apache.wicket.request.resource.IResource;
030import org.apache.wicket.request.resource.ResourceReference;
031
032/**
033 * This resource reference is used to provide a reference to a resource based on Java NIO FileSystem
034 * API.<br>
035 * <br>
036 * To implement a mime type detection refer to the documentation of
037 * {@link java.nio.file.Files#probeContentType(Path)} and provide an implementation for
038 * java.nio.file.spi.FileTypeDetector in the META-INF/services folder for jars or in the
039 * /WEB-INF/classes/META-INF/services folder for webapps<br>
040 * <br>
041 * You can optionally override {@link #getFileSystemResource()} to provide an inline mime type
042 * detection, which is preferred to the default detection.<br>
043 * <br>
044 * Example:
045 * 
046 * <pre>
047 * <code>
048 * Path path = FileSystemResourceReference.getPath(URI.create("jar:file:///folder/file.zip!/folderInZip/video.mp4"));
049 * add(new Video("video", new FileSystemResourceReference(path)));
050 * </code>
051 * </pre>
052 * 
053 * Example 2:
054 * 
055 * <pre>
056 * <code>
057 * mountResource("/filecontent/${name}", new FileSystemResourceReference("filesystem")
058 * {
059 *      private static final long serialVersionUID = 1L;
060 * 
061 *      {@literal @}Override
062 *      public IResource getResource()
063 *      {
064 *              return new FileSystemResource()
065 *              {
066 *                      private static final long serialVersionUID = 1L;
067 * 
068 *                      protected ResourceResponse newResourceResponse(Attributes attributes)
069 *                      {
070 *                              try
071 *                              {
072 *                                      String name = attributes.getParameters().get("name").toString("");
073 *                                      URI uri = URI.create(
074 *                                              "jar:file:////folder/example.zip!/zipfolder/" + name);
075 *                                      return createResourceResponse(attributes, 
076 *                                              FileSystemResourceReference.getPath(uri));
077 *                              }
078 *                              catch (IOException | URISyntaxException e)
079 *                              {
080 *                                      throw new WicketRuntimeException("Error while reading the file.", e);
081 *                              }
082 *                      };
083 *              };
084 *      }
085 * });
086 * </code>
087 * </pre>
088 * 
089 * @author Tobias Soloschenko
090 */
091public class FileSystemResourceReference extends ResourceReference
092{
093        private static final long serialVersionUID = 1L;
094
095        private Path path;
096
097        /**
098         * Creates a file system resource reference based on the given path
099         * 
100         * @param name
101         *            the name of the resource reference to expose data
102         * @param path
103         *            the path to create the resource reference
104         */
105        public FileSystemResourceReference(String name, Path path)
106        {
107                super(name);
108                this.path = path;
109        }
110
111        /**
112         * Creates a file system resource reference based on the given name
113         * 
114         * @param name
115         *            the name of the resource reference
116         * 
117         */
118        public FileSystemResourceReference(String name)
119        {
120                super(name);
121        }
122
123        /**
124         * Creates a file system resource reference based on the given scope and name
125         * 
126         * @param scope
127         *            the scope as class
128         * @param name
129         *            the name of the resource reference
130         * 
131         */
132        public FileSystemResourceReference(Class<?> scope, String name)
133        {
134                super(scope, name);
135        }
136
137        /**
138         * Creates a new {@link FileSystemResource} and applies the
139         * path to it.
140         */
141        @Override
142        public IResource getResource()
143        {
144                return getFileSystemResource();
145        }
146
147        /**
148         * Gets the file system resource to be used for the resource reference
149         * 
150         * @return the file system resource to be used for the resource reference
151         */
152        protected FileSystemResource getFileSystemResource()
153        {
154                if (path == null)
155                {
156                        throw new WicketRuntimeException(
157                                "Please override #getResource() and provide a path if using a constructor which doesn't take one as argument.");
158                }
159                return new FileSystemResource(path);
160        }
161
162        /**
163         * Creates a path and a file system (if required) based on the given URI
164         * 
165         * @param uri
166         *            the URI to create the file system and the path of
167         * @param env
168         *            the environment parameter to create the file system with
169         * @return the path of the file in the file system
170         */
171        public static Path getPath(URI uri, Map<String, String> env)
172        {
173                Iterator<FileSystemPathService> pathServiceIterator = ServiceLoader
174                        .load(FileSystemPathService.class).iterator();
175                while (pathServiceIterator.hasNext())
176                {
177                        FileSystemPathService pathService = pathServiceIterator.next();
178                        if (pathService.isResponsible(uri))
179                        {
180                                Path fileSystemPath = pathService.getPath(uri, env);
181                                if (fileSystemPath != null)
182                                {
183                                        return fileSystemPath;
184                                }
185                        }
186                }
187                // fall back to just get the path from the URI
188                return Paths.get(uri);
189        }
190
191        /**
192         * Creates a path and a file system (if required) based on the given URI
193         * 
194         * @param uri
195         *            the URI to create the file system and the path of
196         * @return the path of the file in the file system
197         * @throws IOException
198         *             if the file system could'nt be created
199         * @throws URISyntaxException
200         *             if the URI has no valid syntax
201         */
202        public static Path getPath(URI uri) throws IOException, URISyntaxException
203        {
204                return getPath(uri, null);
205        }
206}