View Javadoc

1   /*
2    * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3    * Copyright (C) 2004-2009 Frederico Caldeira Knabben
4    * 
5    * == BEGIN LICENSE ==
6    * 
7    * Licensed under the terms of any of the following licenses at your
8    * choice:
9    * 
10   *  - GNU General Public License Version 2 or later (the "GPL")
11   *    http://www.gnu.org/licenses/gpl.html
12   * 
13   *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
14   *    http://www.gnu.org/licenses/lgpl.html
15   * 
16   *  - Mozilla Public License Version 1.1 or later (the "MPL")
17   *    http://www.mozilla.org/MPL/MPL-1.1.html
18   * 
19   * == END LICENSE ==
20   */
21  package net.fckeditor.connector.impl;
22  
23  import java.io.File;
24  import java.io.FileFilter;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  import javax.servlet.ServletContext;
35  
36  import net.fckeditor.connector.Connector;
37  import net.fckeditor.connector.exception.FolderAlreadyExistsException;
38  import net.fckeditor.connector.exception.InvalidCurrentFolderException;
39  import net.fckeditor.connector.exception.InvalidNewFolderNameException;
40  import net.fckeditor.connector.exception.WriteException;
41  import net.fckeditor.handlers.RequestCycleHandler;
42  import net.fckeditor.handlers.ResourceType;
43  import net.fckeditor.requestcycle.ThreadLocalData;
44  import net.fckeditor.requestcycle.UserPathBuilder;
45  import net.fckeditor.tool.UtilsFile;
46  
47  import org.apache.commons.io.IOUtils;
48  import org.apache.commons.io.filefilter.DirectoryFileFilter;
49  import org.apache.commons.io.filefilter.FileFileFilter;
50  
51  /**
52   * Abstract local filesystem backend connector. This class is the default
53   * implementation of the <a href="http://docs.fckeditor.net/FCKeditor_2.x/Developers_Guide/Server_Side_Integration"
54   * target="_blank">official connector specification</a>.
55   * <p>
56   * It serves files and folders against a specific local directory which is
57   * resolved in a subclass. You cannot use this class directly, instead you have
58   * to subclass it and implement the abstract methods and override methods if
59   * necessary.
60   * 
61   * @version $Id: AbstractLocalFileSystemConnector.java 3695 2009-06-18 20:18:38Z mosipov $
62   */
63  public abstract class AbstractLocalFileSystemConnector implements Connector {
64  
65  	protected ServletContext servletContext;
66  
67  	public String fileUpload(final ResourceType type,
68  			final String currentFolder, final String fileName,
69  			final InputStream inputStream)
70  			throws InvalidCurrentFolderException, WriteException {
71  		String absolutePath = getRealUserFilesAbsolutePath(RequestCycleHandler
72  				.getUserFilesAbsolutePath(ThreadLocalData.getRequest()));
73  		File typeDir = getOrCreateResourceTypeDir(absolutePath, type);
74  		File currentDir = new File(typeDir, currentFolder);
75  		if (!currentDir.exists() || !currentDir.isDirectory())
76  			throw new InvalidCurrentFolderException();
77  
78  		File newFile = new File(currentDir, fileName);
79  		File fileToSave = UtilsFile.getUniqueFile(newFile.getAbsoluteFile());
80  
81  		try {
82  			IOUtils.copyLarge(inputStream, new FileOutputStream(fileToSave));
83  		} catch (IOException e) {
84  			throw new WriteException();
85  		}
86  		return fileToSave.getName();
87  	}
88  
89  	public void createFolder(final ResourceType type,
90  			final String currentFolder, final String newFolder)
91  			throws InvalidCurrentFolderException,
92  			InvalidNewFolderNameException, FolderAlreadyExistsException {
93  		String absolutePath = getRealUserFilesAbsolutePath(RequestCycleHandler
94  				.getUserFilesAbsolutePath(ThreadLocalData.getRequest()));
95  		File typeDir = getOrCreateResourceTypeDir(absolutePath, type);
96  		File currentDir = new File(typeDir, currentFolder);
97  		if (!currentDir.exists() || !currentDir.isDirectory())
98  			throw new InvalidCurrentFolderException();
99  
100 		File newDir = new File(currentDir, newFolder);
101 		if (newDir.exists())
102 			throw new FolderAlreadyExistsException();
103 		if (!newDir.mkdir())
104 			throw new InvalidNewFolderNameException();
105 	}
106 
107 	public List<Map<String, Object>> getFiles(ResourceType type,
108 			String currentFolder) throws InvalidCurrentFolderException {
109 		String absolutePath = getRealUserFilesAbsolutePath(RequestCycleHandler
110 				.getUserFilesAbsolutePath(ThreadLocalData.getRequest()));
111 		File typeDir = getOrCreateResourceTypeDir(absolutePath, type);
112 		File currentDir = new File(typeDir, currentFolder);
113 		if (!currentDir.exists() || !currentDir.isDirectory())
114 			throw new InvalidCurrentFolderException();
115 
116 		// collect files
117 		List<Map<String, Object>> files;
118 		Map<String, Object> fileMap;
119 		File[] fileList = currentDir
120 				.listFiles((FileFilter) FileFileFilter.FILE);
121 		files = new ArrayList<Map<String, Object>>(fileList.length);
122 		for (File file : fileList) {
123 			fileMap = new HashMap<String, Object>(2);
124 			fileMap.put(Connector.KEY_NAME, file.getName());
125 			fileMap.put(Connector.KEY_SIZE, file.length());
126 			files.add(fileMap);
127 		}
128 		return files;
129 	}
130 
131 	public List<String> getFolders(final ResourceType type,
132 			final String currentFolder) throws InvalidCurrentFolderException {
133 		String absolutePath = getRealUserFilesAbsolutePath(RequestCycleHandler
134 				.getUserFilesAbsolutePath(ThreadLocalData.getRequest()));
135 		File typeDir = getOrCreateResourceTypeDir(absolutePath, type);
136 		File currentDir = new File(typeDir, currentFolder);
137 		if (!currentDir.exists() || !currentDir.isDirectory())
138 			throw new InvalidCurrentFolderException();
139 
140 		String[] fileList = currentDir.list(DirectoryFileFilter.DIRECTORY);
141 		return Arrays.asList(fileList);
142 	}
143 
144 	/**
145 	 * Resolves a provided userfiles absolute path against a specific backend.
146 	 * The is no restriction how to resolve the path. To keep it simple, you may
147 	 * use
148 	 * {@link UserPathBuilder#getUserFilesAbsolutePath(javax.servlet.http.HttpServletRequest) UserPathBuilder.getUserFilesAbsolutePath}.
149 	 * The return value has to be consistent within the entire request cycle.
150 	 * 
151 	 * @param userFilesAbsolutePath
152 	 *            the userfiles absolute path to resolve against a specific
153 	 *            backend
154 	 * @return the resolved userfiles absolute path
155 	 */
156 	protected abstract String getRealUserFilesAbsolutePath(String userFilesAbsolutePath);
157 
158 	/**
159 	 * Returns a file reference to a created resource type directory. The
160 	 * directory will be created only if it does not exist.
161 	 * 
162 	 * @param baseDir
163 	 *            the current resource type's base directory
164 	 * @param type
165 	 *            the current resource type
166 	 * @return a file reference the resource type directory
167 	 */
168 	protected static File getOrCreateResourceTypeDir(final String baseDir,
169 			final ResourceType type) {
170 		File dir = new File(baseDir, type.getPath());
171 		if (!dir.exists())
172 			dir.mkdirs();
173 		return dir;
174 	}
175 }