Subversion Repositories XServices

Rev

Rev 109 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 109 Rev 147
-
 
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;
2
 
18
 
3
import java.io.File;
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;
-
 
28
import java.nio.file.FileVisitResult;
4
import java.io.FileFilter;
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;
-
 
34
import java.nio.file.attribute.BasicFileAttributes;
5
import java.util.ArrayList;
35
import java.util.ArrayList;
-
 
36
import java.util.EnumSet;
6
import java.util.List;
37
import java.util.List;
-
 
38
import java.util.zip.ZipEntry;
-
 
39
import java.util.zip.ZipOutputStream;
-
 
40
 
-
 
41
import javax.ws.rs.NotAuthorizedException;
-
 
42
import javax.ws.rs.WebApplicationException;
7
import javax.ws.rs.core.GenericEntity;
43
import javax.ws.rs.core.GenericEntity;
8
import javax.ws.rs.core.HttpHeaders;
44
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;
10
import net.brutex.xservices.security.StandardSecurityManager;
47
import javax.ws.rs.core.StreamingOutput;
-
 
48
import javax.ws.rs.core.UriInfo;
-
 
49
 
11
import net.brutex.xservices.security.UserIdentity;
50
import net.brutex.xservices.security.DirectoryPermission;
12
import net.brutex.xservices.types.FileInfoType;
51
import net.brutex.xservices.types.FileInfoType;
-
 
52
import net.brutex.xservices.util.FileWalker;
13
 
53
 
14
import org.apache.jcs.JCS;
54
import org.apache.jcs.JCS;
15
import org.apache.jcs.access.exception.CacheException;
55
import org.apache.jcs.access.exception.CacheException;
-
 
56
import org.apache.log4j.Logger;
-
 
57
import org.apache.shiro.SecurityUtils;
-
 
58
import org.apache.shiro.authz.UnauthorizedException;
16
 
59
 
17
/**
60
/**
18
 * @author Brian Rosenberger, bru(at)brutex.de
61
 * The Class FileInfoImpl.
-
 
62
 *
19
 *
63
 * @author Brian Rosenberger, bru(at)brutex.de
20
 */
64
 */
-
 
65
public class FileInfoImpl  implements FileInfo {
-
 
66
	
-
 
67
	
-
 
68
	Logger logger = Logger.getLogger(FileInfoImpl.class);
21
public class FileInfoImpl  implements FileInfo
69
	
-
 
70
 
-
 
71
  /* (non-Javadoc)
-
 
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();
77
	isPermitted(dir);
27
 
78
	
28
    if (!sec.canExecute(java.lang.Thread.currentThread().getStackTrace()[1].getMethodName(), id)) {
-
 
29
      return null;
-
 
30
    }
79
    URI baseuri = URI.create(uriInfo.getBaseUri()+FileInfo.BASE_PATH+"getFile?file=");
-
 
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
 
35
    if ((!withDir) && (!withFiles)) withFiles = true;
85
    if ((!withDir) && (!withFiles)) withFiles = true;
36
    String cachekey = level + "||" + withFiles + "||" + withDir + "||" + search + "||" + dir;
86
    String cachekey = level + "||" + withFiles + "||" + withDir + "||" + search + "||" + dir;
37
    try {
87
    try {
-
 
88
      logger.debug(String.format("Hitting cache with cachekey '%s'", cachekey));
38
      JCS jcs = JCS.getInstance("FileCache");
89
      JCS jcs = JCS.getInstance("FileCache");
-
 
90
 
39
 
91
      /*Try to retrieve the file list from the cache*/
-
 
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);
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;
104
      fromIndex = (page - 1) * count;
52
      toIndex = page * count;
105
      toIndex = page * count;
53
      if (toIndex > list.size()) toIndex = list.size();
106
      if (toIndex > list.size()) toIndex = list.size();
54
      if (fromIndex > toIndex) fromIndex = toIndex;
107
      if (fromIndex > toIndex) fromIndex = toIndex;
55
      GenericEntity sublist = new GenericEntity(list.subList(fromIndex, toIndex))
108
      GenericEntity<List<FileInfoType>> sublist = new GenericEntity<List<FileInfoType>>(list.subList(fromIndex, toIndex)) {};
56
      {
-
 
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();
59
    } catch (CacheException e) {
111
    } catch (CacheException e) {
60
      Response.serverError().build();
112
      Response.serverError().build();
61
    }
113
    }
62
    return null;
114
    return null;
63
  }
115
  }
-
 
116
 
-
 
117
  /**
-
 
118
   * Sets the directory.
-
 
119
   *
-
 
120
   * @param list the list
-
 
121
   * @param dir the dir
-
 
122
   * @param withDirectories the with directories
-
 
123
   * @param withFiles the with files
-
 
124
   * @param depth the depth
-
 
125
   * @param search the search
64
 
126
   */
65
  private void setDirectory(List<FileInfoType> list, File dir, boolean withDirectories, boolean withFiles, final int depth, final String search)
127
  private void setDirectory(final URI baseuri, final List<FileInfoType> list, File dir, boolean withDirectories, boolean withFiles, final int depth, String search)
66
  {
128
  {
67
    if (depth <= 0) return;
129
    if (depth <= 0) return;
68
 
-
 
69
    File[] files = dir.listFiles(new FileFilter()
-
 
70
    {
-
 
71
      public boolean accept(File pathname) {
-
 
72
        if ((pathname.isDirectory()) && (depth > 1)) return true;
130
    
73
        if ((search == null) || (search.equals(""))) return true;
-
 
74
        if (!pathname.getAbsolutePath().contains(search)) return false;
131
    	if(search==null || search.equals("") ) {
-
 
132
    		search = "*";
75
        return true;
133
    		logger.info("No search pattern supplied, using default '*'.");
76
      }
-
 
77
    });
-
 
78
    if ((dir.getParentFile() != null) && (withDirectories)) list.add(new FileInfoType(dir.getParentFile()));
-
 
79
    if (files == null) return;
134
    	}
80
 
135
    	
-
 
136
    	FileWalker finder = new FileWalker(search);
81
    for (File e : files) {
137
    	try {
-
 
138
			Files.walkFileTree(dir.toPath(), EnumSet.of(FileVisitOption.FOLLOW_LINKS), depth, finder);
82
      if (e.isDirectory()) setDirectory(list, e, withDirectories, withFiles, depth - 1, search);
139
			logger.info("FileWalker returned '"+finder.getCount()+"' hits. '" + finder.getTotal() + "' files have been scanned.");
83
      if (((withDirectories) && (e.isDirectory())) || (
140
			List<Path> result = finder.getResult();
84
        (withFiles) && (e.isFile())))
141
	    	for(Path f : result) {
85
        list.add(new FileInfoType(e));
142
	    		list.add(new FileInfoType(f, baseuri));
-
 
143
	    	}
-
 
144
		} catch (IOException e2) {
-
 
145
			logger.error(e2.getMessage(), e2);;
86
    }
146
		}
87
  }
147
  }
-
 
148
  
-
 
149
  /**
-
 
150
   * Sets the directory.
-
 
151
   *
-
 
152
   * @param dir the dir
-
 
153
   * @param withDirectories the with directories
-
 
154
   * @param withFiles the with files
-
 
155
   * @param depth the depth
-
 
156
   * @param search the search
-
 
157
   * @return the list
88
 
158
   */
89
  private List<FileInfoType> setDirectory(String dir, boolean withDirectories, boolean withFiles, int depth, String search)
159
  private List<FileInfoType> setDirectory(URI baseuri, String dir, boolean withDirectories, boolean withFiles, int depth, String search)
90
  {
160
  {
91
    List list = new ArrayList();
161
    List<FileInfoType> list = new ArrayList<FileInfoType>();
92
    setDirectory(list, new File(dir), withDirectories, withFiles, depth, search);
162
    setDirectory(baseuri, list, new File(dir), withDirectories, withFiles, depth, search);
93
    return list;
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) {
-
 
245
	if(! SecurityUtils.getSubject().isPermitted( new DirectoryPermission(dir))) {
-
 
246
		logger.warn(String.format("User '%s' does not have permission to access '%s'.",SecurityUtils.getSubject().getPrincipal(), dir ));
-
 
247
		throw new NotAuthorizedException(new UnauthorizedException("User does not have permission to access "+ dir));
-
 
248
	}
-
 
249
	return true;
94
  }
250
}
95
}
251
}
96
 
252
 
97
Generated by GNU Enscript 1.6.5.90.
253
Generated by GNU Enscript 1.6.5.90.
98
 
254
 
99
 
255