Subversion Repositories XServices

Rev

Rev 109 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 109 Rev 147
Line -... Line 1...
-
 
1
/*
-
 
2
 *   Copyright 2013 Brian Rosenberger (Brutex Network)
-
 
3
 *
-
 
4
 *   Licensed under the Apache License, Version 2.0 (the "License");
-
 
5
 *   you may not use this file except in compliance with the License.
-
 
6
 *   You may obtain a copy of the License at
-
 
7
 *
-
 
8
 *       http://www.apache.org/licenses/LICENSE-2.0
-
 
9
 *
-
 
10
 *   Unless required by applicable law or agreed to in writing, software
-
 
11
 *   distributed under the License is distributed on an "AS IS" BASIS,
-
 
12
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-
 
13
 *   See the License for the specific language governing permissions and
-
 
14
 *   limitations under the License.
-
 
15
 */
-
 
16
 
1
package net.brutex.xservices.ws.rs;
17
package net.brutex.xservices.ws.rs;
Line 2... Line 18...
2
 
18
 
-
 
19
import java.io.File;
-
 
20
import java.io.FileInputStream;
-
 
21
import java.io.FileOutputStream;
-
 
22
import java.io.IOException;
-
 
23
import java.io.OutputStream;
-
 
24
import java.net.URI;
-
 
25
import java.nio.file.DirectoryStream;
-
 
26
import java.nio.file.FileSystems;
-
 
27
import java.nio.file.FileVisitOption;
3
import java.io.File;
28
import java.nio.file.FileVisitResult;
-
 
29
import java.nio.file.Files;
-
 
30
import java.nio.file.Path;
-
 
31
import java.nio.file.PathMatcher;
-
 
32
import java.nio.file.SimpleFileVisitor;
-
 
33
import java.nio.file.attribute.BasicFileAttributeView;
4
import java.io.FileFilter;
34
import java.nio.file.attribute.BasicFileAttributes;
-
 
35
import java.util.ArrayList;
5
import java.util.ArrayList;
36
import java.util.EnumSet;
-
 
37
import java.util.List;
-
 
38
import java.util.zip.ZipEntry;
-
 
39
import java.util.zip.ZipOutputStream;
-
 
40
 
-
 
41
import javax.ws.rs.NotAuthorizedException;
6
import java.util.List;
42
import javax.ws.rs.WebApplicationException;
7
import javax.ws.rs.core.GenericEntity;
43
import javax.ws.rs.core.GenericEntity;
-
 
44
import javax.ws.rs.core.HttpHeaders;
8
import javax.ws.rs.core.HttpHeaders;
45
import javax.ws.rs.core.MediaType;
9
import javax.ws.rs.core.Response;
46
import javax.ws.rs.core.Response;
-
 
47
import javax.ws.rs.core.StreamingOutput;
-
 
48
import javax.ws.rs.core.UriInfo;
10
import net.brutex.xservices.security.StandardSecurityManager;
49
 
11
import net.brutex.xservices.security.UserIdentity;
50
import net.brutex.xservices.security.DirectoryPermission;
-
 
51
import net.brutex.xservices.types.FileInfoType;
Line 12... Line 52...
12
import net.brutex.xservices.types.FileInfoType;
52
import net.brutex.xservices.util.FileWalker;
13
 
53
 
-
 
54
import org.apache.jcs.JCS;
-
 
55
import org.apache.jcs.access.exception.CacheException;
-
 
56
import org.apache.log4j.Logger;
Line 14... Line 57...
14
import org.apache.jcs.JCS;
57
import org.apache.shiro.SecurityUtils;
15
import org.apache.jcs.access.exception.CacheException;
58
import org.apache.shiro.authz.UnauthorizedException;
16
 
59
 
-
 
60
/**
17
/**
61
 * The Class FileInfoImpl.
18
 * @author Brian Rosenberger, bru(at)brutex.de
62
 *
-
 
63
 * @author Brian Rosenberger, bru(at)brutex.de
-
 
64
 */
-
 
65
public class FileInfoImpl  implements FileInfo {
-
 
66
	
19
 *
67
	
-
 
68
	Logger logger = Logger.getLogger(FileInfoImpl.class);
-
 
69
	
-
 
70
 
20
 */
71
  /* (non-Javadoc)
21
public class FileInfoImpl  implements FileInfo
72
   * @see net.brutex.xservices.ws.rs.FileInfo#getFiles(javax.ws.rs.core.HttpHeaders, java.lang.String, boolean, boolean, int, java.lang.String, int, int)
22
{
-
 
-
 
73
   */
23
  public Response getFiles(HttpHeaders h, String dir, boolean withDir, boolean withFiles, int level, String search, int count, int page)
74
  public Response getFiles(HttpHeaders h, UriInfo uriInfo, String dir, boolean withDir, boolean withFiles, int level, String search, int count, int page, boolean useCache)
24
  {
75
  {
25
    StandardSecurityManager sec = new StandardSecurityManager();
76
	
26
    UserIdentity id = new UserIdentity();
-
 
27
 
-
 
28
    if (!sec.canExecute(java.lang.Thread.currentThread().getStackTrace()[1].getMethodName(), id)) {
77
	isPermitted(dir);
-
 
78
	
29
      return null;
79
    URI baseuri = URI.create(uriInfo.getBaseUri()+FileInfo.BASE_PATH+"getFile?file=");
30
    }
80
    
31
 
-
 
-
 
81
    if(dir==null) {dir = "c:/"; System.out.println("No directory specified.");}
32
    System.out.println("Listing directory: " + dir);
82
    logger.info(String.format("Listing directory '%s'.", dir));
33
    if (level <= 0) level = 1;
83
    if (level <= 0) level = 1;
34
    if (level > 3) level = 3;
84
 
-
 
85
    if ((!withDir) && (!withFiles)) withFiles = true;
35
    if ((!withDir) && (!withFiles)) withFiles = true;
86
    String cachekey = level + "||" + withFiles + "||" + withDir + "||" + search + "||" + dir;
Line -... Line 87...
-
 
87
    try {
36
    String cachekey = level + "||" + withFiles + "||" + withDir + "||" + search + "||" + dir;
88
      logger.debug(String.format("Hitting cache with cachekey '%s'", cachekey));
-
 
89
      JCS jcs = JCS.getInstance("FileCache");
37
    try {
90
 
38
      JCS jcs = JCS.getInstance("FileCache");
91
      /*Try to retrieve the file list from the cache*/
39
 
92
      List<FileInfoType> list = (List<FileInfoType>)jcs.get(cachekey);
40
      List list = (List)jcs.get(cachekey);
93
      
41
      if (list == null) {
94
      if (list == null || !useCache) {
42
        list = setDirectory(dir, withDir, withFiles, level, search);
95
        list = setDirectory(baseuri, dir, withDir, withFiles, level, search);
43
        jcs.put(cachekey, list);
96
        jcs.put(cachekey, list);
Line 44... Line 97...
44
        System.out.println("Stored in Cache: " + list.toString());
97
        logger.debug("Stored in Cache: " + list.toString());
45
      } else {
98
      } else {
46
        System.out.println("Got from Cache: " + list.toString());
99
        logger.debug("Got from Cache: " + list.toString());
47
      }
100
      }
48
 
101
 
49
      int fromIndex = 0;
102
      int fromIndex = 0;
50
      int toIndex = 0;
103
      int toIndex = 0;
51
      fromIndex = (page - 1) * count;
-
 
52
      toIndex = page * count;
-
 
-
 
104
      fromIndex = (page - 1) * count;
53
      if (toIndex > list.size()) toIndex = list.size();
105
      toIndex = page * count;
54
      if (fromIndex > toIndex) fromIndex = toIndex;
106
      if (toIndex > list.size()) toIndex = list.size();
55
      GenericEntity sublist = new GenericEntity(list.subList(fromIndex, toIndex))
107
      if (fromIndex > toIndex) fromIndex = toIndex;
56
      {
108
      GenericEntity<List<FileInfoType>> sublist = new GenericEntity<List<FileInfoType>>(list.subList(fromIndex, toIndex)) {};
57
      };
109
      logger.info(String.format("Returning items %s to %s from total of %s items in the list.", fromIndex, toIndex, list.size()));
58
      return Response.ok(sublist).build();
110
      return Response.ok(sublist).build();
Line -... Line 111...
-
 
111
    } catch (CacheException e) {
-
 
112
      Response.serverError().build();
-
 
113
    }
-
 
114
    return null;
-
 
115
  }
-
 
116
 
-
 
117
  /**
-
 
118
   * Sets the directory.
-
 
119
   *
-
 
120
   * @param list the list
59
    } catch (CacheException e) {
121
   * @param dir the dir
60
      Response.serverError().build();
122
   * @param withDirectories the with directories
61
    }
123
   * @param withFiles the with files
62
    return null;
124
   * @param depth the depth
63
  }
-
 
64
 
-
 
65
  private void setDirectory(List<FileInfoType> list, File dir, boolean withDirectories, boolean withFiles, final int depth, final String search)
-
 
66
  {
-
 
67
    if (depth <= 0) return;
125
   * @param search the search
68
 
-
 
69
    File[] files = dir.listFiles(new FileFilter()
126
   */
-
 
127
  private void setDirectory(final URI baseuri, final List<FileInfoType> list, File dir, boolean withDirectories, boolean withFiles, final int depth, String search)
70
    {
128
  {
71
      public boolean accept(File pathname) {
-
 
72
        if ((pathname.isDirectory()) && (depth > 1)) return true;
-
 
73
        if ((search == null) || (search.equals(""))) return true;
-
 
74
        if (!pathname.getAbsolutePath().contains(search)) return false;
129
    if (depth <= 0) return;
75
        return true;
130
    
-
 
131
    	if(search==null || search.equals("") ) {
76
      }
132
    		search = "*";
-
 
133
    		logger.info("No search pattern supplied, using default '*'.");
77
    });
134
    	}
78
    if ((dir.getParentFile() != null) && (withDirectories)) list.add(new FileInfoType(dir.getParentFile()));
135
    	
79
    if (files == null) return;
136
    	FileWalker finder = new FileWalker(search);
80
 
137
    	try {
-
 
138
			Files.walkFileTree(dir.toPath(), EnumSet.of(FileVisitOption.FOLLOW_LINKS), depth, finder);
-
 
139
			logger.info("FileWalker returned '"+finder.getCount()+"' hits. '" + finder.getTotal() + "' files have been scanned.");
-
 
140
			List<Path> result = finder.getResult();
81
    for (File e : files) {
141
	    	for(Path f : result) {
82
      if (e.isDirectory()) setDirectory(list, e, withDirectories, withFiles, depth - 1, search);
142
	    		list.add(new FileInfoType(f, baseuri));
-
 
143
	    	}
-
 
144
		} catch (IOException e2) {
-
 
145
			logger.error(e2.getMessage(), e2);;
-
 
146
		}
-
 
147
  }
-
 
148
  
-
 
149
  /**
-
 
150
   * Sets the directory.
-
 
151
   *
-
 
152
   * @param dir the dir
83
      if (((withDirectories) && (e.isDirectory())) || (
153
   * @param withDirectories the with directories
84
        (withFiles) && (e.isFile())))
154
   * @param withFiles the with files
85
        list.add(new FileInfoType(e));
155
   * @param depth the depth
86
    }
156
   * @param search the search
87
  }
157
   * @return the list
88
 
158
   */
-
 
159
  private List<FileInfoType> setDirectory(URI baseuri, String dir, boolean withDirectories, boolean withFiles, int depth, String search)
-
 
160
  {
-
 
161
    List<FileInfoType> list = new ArrayList<FileInfoType>();
-
 
162
    setDirectory(baseuri, list, new File(dir), withDirectories, withFiles, depth, search);
-
 
163
    return list;
-
 
164
  }
-
 
165
 
-
 
166
@Override
-
 
167
public Response getFile(HttpHeaders paramHttpHeaders, String file) {
-
 
168
	isPermitted(file);
-
 
169
	try {
-
 
170
	Path path = FileSystems.getDefault().getPath(file);
-
 
171
	
-
 
172
	BasicFileAttributeView basicView = Files.getFileAttributeView(path, BasicFileAttributeView.class);
-
 
173
	BasicFileAttributes basic;
-
 
174
	basic = basicView.readAttributes();
-
 
175
	
-
 
176
	
-
 
177
	//In case this is a directory
-
 
178
	//we zip it and return the zip stream
-
 
179
	if(basic.isDirectory()) return getDirectoryAsZip(path);
-
 
180
	
-
 
181
	
-
 
182
	
-
 
183
	MediaType mime = MediaType.APPLICATION_OCTET_STREAM_TYPE;
-
 
184
	try {
-
 
185
		mime = MediaType.valueOf(Files.probeContentType(path));
-
 
186
	} catch (IllegalArgumentException | IOException e) {
-
 
187
		//In case we can not find the media type for some reason
-
 
188
		//the default assignment is taken, so we can
-
 
189
		//ignore this error.
-
 
190
		logger.debug(String.format("Could not probe media type for file '%s'. Default is '%s'", path.toString(), mime.getType()), e);
-
 
191
	}
-
 
192
	Response r = Response.ok(path.toFile(), mime).build();
-
 
193
	String fileName = path.getFileName().toString();
-
 
194
	if(mime == MediaType.APPLICATION_OCTET_STREAM_TYPE) r.getHeaders().add("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
-
 
195
	return r;
-
 
196
		} catch (IOException e1) {
-
 
197
			// TODO Auto-generated catch block
-
 
198
			logger.error(e1.getMessage(), e1);
-
 
199
			return Response.serverError().build();
-
 
200
		}
-
 
201
}
-
 
202
 
-
 
203
private Response getDirectoryAsZip(final Path path) {
-
 
204
 
-
 
205
	StreamingOutput output = new StreamingOutput() {
-
 
206
		
-
 
207
		@Override
-
 
208
		public void write(OutputStream os) throws IOException,
-
 
209
				WebApplicationException {
-
 
210
			ZipOutputStream zos = new ZipOutputStream(os);
-
 
211
			
-
 
212
			//read directory content (files only)
-
 
213
			try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
-
 
214
			    for (Path file: stream) {
-
 
215
			    	//skip anything not being a file
-
 
216
			        if(! file.toFile().isFile()) continue;
-
 
217
			        
-
 
218
			        //ZipEntry
-
 
219
			        String filename = file.getFileName().toString();
-
 
220
			        ZipEntry ze = new ZipEntry(filename);
-
 
221
			        zos.putNextEntry( ze );
-
 
222
			        
-
 
223
			        //read a file and put it into the output stream
-
 
224
			        FileInputStream fis = new FileInputStream(file.toFile());
-
 
225
			        byte[] buffer = new byte[1024];
-
 
226
			        int len;
-
 
227
			        while ((len = fis.read(buffer)) > 0) {
-
 
228
			        	zos.write(buffer, 0, len);
-
 
229
			        }
-
 
230
			        zos.flush();
-
 
231
			        fis.close();
-
 
232
			    }
-
 
233
			    zos.close();
-
 
234
			}
-
 
235
			
-
 
236
		}
-
 
237
	};
-
 
238
	Response r = Response.ok(output, MediaType.APPLICATION_OCTET_STREAM_TYPE).build();
-
 
239
	String zipname = (path.getFileName()==null) ? "null.zip" : path.getFileName().toString()+".zip";
-
 
240
	r.getHeaders().add("Content-Disposition", "attachment; filename=\"" + zipname + "\"");
-
 
241
	return r;
-
 
242
}
-
 
243
 
-
 
244
private boolean isPermitted(String dir) {
89
  private List<FileInfoType> setDirectory(String dir, boolean withDirectories, boolean withFiles, int depth, String search)
245
	if(! SecurityUtils.getSubject().isPermitted( new DirectoryPermission(dir))) {
90
  {
246
		logger.warn(String.format("User '%s' does not have permission to access '%s'.",SecurityUtils.getSubject().getPrincipal(), dir ));